4 * Copyright(c) 2006-2007, Ext JS, LLC.
6 * Originally Released Under LGPL - original licence link has changed is not relivant.
9 * <script type="text/javascript">
17 window["undefined"] = window["undefined"];
21 * Roo core utilities and functions.
26 * Copies all the properties of config to obj.
27 * @param {Object} obj The receiver of the properties
28 * @param {Object} config The source of the properties
29 * @param {Object} defaults A different object that will also be applied for default values
30 * @return {Object} returns obj
35 Roo.apply = function(o, c, defaults){
37 // no "this" reference for friendly out of scope calls
38 Roo.apply(o, defaults);
40 if(o && c && typeof c == 'object'){
51 var ua = navigator.userAgent.toLowerCase();
53 var isStrict = document.compatMode == "CSS1Compat",
54 isOpera = ua.indexOf("opera") > -1,
55 isSafari = (/webkit|khtml/).test(ua),
56 isFirefox = ua.indexOf("firefox") > -1,
57 isIE = ua.indexOf("msie") > -1,
58 isIE7 = ua.indexOf("msie 7") > -1,
59 isIE11 = /trident.*rv\:11\./.test(ua),
60 isEdge = ua.indexOf("edge") > -1,
61 isGecko = !isSafari && ua.indexOf("gecko") > -1,
62 isBorderBox = isIE && !isStrict,
63 isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
64 isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
65 isLinux = (ua.indexOf("linux") != -1),
66 isSecure = window.location.href.toLowerCase().indexOf("https") === 0,
67 isIOS = /iphone|ipad/.test(ua),
68 isAndroid = /android/.test(ua),
69 isTouch = (function() {
71 if (ua.indexOf('chrome') != -1 && ua.indexOf('android') == -1) {
72 window.addEventListener('touchstart', function __set_has_touch__ () {
74 window.removeEventListener('touchstart', __set_has_touch__);
76 return false; // no touch on chrome!?
78 document.createEvent("TouchEvent");
85 // remove css image flicker
88 document.execCommand("BackgroundImageCache", false, true);
94 * True if the browser is in strict mode
99 * True if the page is running over SSL
104 * True when the document is fully initialized and ready for action
109 * Turn on debugging output (currently only the factory uses this)
116 * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
119 enableGarbageCollector : true,
122 * True to automatically purge event listeners after uncaching an element (defaults to false).
123 * Note: this only happens if enableGarbageCollector is true.
126 enableListenerCollection:false,
129 * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
130 * the IE insecure content warning (defaults to javascript:false).
133 SSL_SECURE_URL : "javascript:false",
136 * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
137 * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
140 BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
142 emptyFn : function(){},
145 * Copies all the properties of config to obj if they don't already exist.
146 * @param {Object} obj The receiver of the properties
147 * @param {Object} config The source of the properties
148 * @return {Object} returns obj
150 applyIf : function(o, c){
153 if(typeof o[p] == "undefined"){ o[p] = c[p]; }
160 * Applies event listeners to elements by selectors when the document is ready.
161 * The event name is specified with an @ suffix.
164 // add a listener for click on all anchors in element with id foo
165 '#foo a@click' : function(e, t){
169 // add the same listener to multiple selectors (separated by comma BEFORE the @)
170 '#foo a, #bar span.some-class@mouseover' : function(){
175 * @param {Object} obj The list of behaviors to apply
177 addBehaviors : function(o){
179 Roo.onReady(function(){
184 var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
186 var parts = b.split('@');
187 if(parts[1]){ // for Object prototype breakers
190 cache[s] = Roo.select(s);
192 cache[s].on(parts[1], o[b]);
199 * Generates unique ids. If the element already has an id, it is unchanged
200 * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
201 * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
202 * @return {String} The generated Id.
204 id : function(el, prefix){
205 prefix = prefix || "roo-gen";
207 var id = prefix + (++idSeed);
208 return el ? (el.id ? el.id : (el.id = id)) : id;
213 * Extends one class with another class and optionally overrides members with the passed literal. This class
214 * also adds the function "override()" to the class that can be used to override
215 * members on an instance.
216 * @param {Object} subclass The class inheriting the functionality
217 * @param {Object} superclass The class being extended
218 * @param {Object} overrides (optional) A literal with members
223 var io = function(o){
228 return function(sb, sp, overrides){
229 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
232 sb = function(){sp.apply(this, arguments);};
234 var F = function(){}, sbp, spp = sp.prototype;
236 sbp = sb.prototype = new F();
240 if(spp.constructor == Object.prototype.constructor){
245 sb.override = function(o){
249 Roo.override(sb, overrides);
255 * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
257 Roo.override(MyClass, {
258 newMethod1: function(){
261 newMethod2: function(foo){
266 * @param {Object} origclass The class to override
267 * @param {Object} overrides The list of functions to add to origClass. This should be specified as an object literal
268 * containing one or more methods.
271 override : function(origclass, overrides){
273 var p = origclass.prototype;
274 for(var method in overrides){
275 p[method] = overrides[method];
280 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
282 Roo.namespace('Company', 'Company.data');
283 Company.Widget = function() { ... }
284 Company.data.CustomStore = function(config) { ... }
286 * @param {String} namespace1
287 * @param {String} namespace2
288 * @param {String} etc
291 namespace : function(){
292 var a=arguments, o=null, i, j, d, rt;
293 for (i=0; i<a.length; ++i) {
297 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
298 for (j=1; j<d.length; ++j) {
299 o[d[j]]=o[d[j]] || {};
305 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
307 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
308 Roo.factory(conf, Roo.data);
310 * @param {String} classname
311 * @param {String} namespace (optional)
315 factory : function(c, ns)
317 // no xtype, no ns or c.xns - or forced off by c.xns
318 if (!c.xtype || (!ns && !c.xns) || (c.xns === false)) { // not enough info...
321 ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
322 if (c.constructor == ns[c.xtype]) {// already created...
326 if (Roo.debug) { Roo.log("Roo.Factory(" + c.xtype + ")"); }
327 var ret = new ns[c.xtype](c);
331 c.xns = false; // prevent recursion..
335 * Logs to console if it can.
337 * @param {String|Object} string
342 if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
349 * Takes an object and converts it to an encoded URL. e.g. Roo.urlEncode({foo: 1, bar: 2}); would return "foo=1&bar=2". Optionally, property values can be arrays, instead of keys and the resulting string that's returned will contain a name/value pair for each array value.
353 urlEncode : function(o){
359 var ov = o[key], k = Roo.encodeURIComponent(key);
360 var type = typeof ov;
361 if(type == 'undefined'){
363 }else if(type != "function" && type != "object"){
364 buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
365 }else if(ov instanceof Array){
367 for(var i = 0, len = ov.length; i < len; i++) {
368 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
379 * Safe version of encodeURIComponent
380 * @param {String} data
384 encodeURIComponent : function (data)
387 return encodeURIComponent(data);
388 } catch(e) {} // should be an uri encode error.
390 if (data == '' || data == null){
393 // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
394 function nibble_to_hex(nibble){
395 var chars = '0123456789ABCDEF';
396 return chars.charAt(nibble);
398 data = data.toString();
400 for(var i=0; i<data.length; i++){
401 var c = data.charCodeAt(i);
402 var bs = new Array();
405 bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
406 bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
407 bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
408 bs[3] = 0x80 | (c & 0x3F);
409 }else if (c > 0x800){
411 bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
412 bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
413 bs[2] = 0x80 | (c & 0x3F);
416 bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
417 bs[1] = 0x80 | (c & 0x3F);
422 for(var j=0; j<bs.length; j++){
424 var hex = nibble_to_hex((b & 0xF0) >>> 4)
425 + nibble_to_hex(b &0x0F);
434 * Takes an encoded URL and and converts it to an object. e.g. Roo.urlDecode("foo=1&bar=2"); would return {foo: 1, bar: 2} or Roo.urlDecode("foo=1&bar=2&bar=3&bar=4", true); would return {foo: 1, bar: [2, 3, 4]}.
435 * @param {String} string
436 * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
437 * @return {Object} A literal with members
439 urlDecode : function(string, overwrite){
440 if(!string || !string.length){
444 var pairs = string.split('&');
445 var pair, name, value;
446 for(var i = 0, len = pairs.length; i < len; i++){
447 pair = pairs[i].split('=');
448 name = decodeURIComponent(pair[0]);
449 value = decodeURIComponent(pair[1]);
450 if(overwrite !== true){
451 if(typeof obj[name] == "undefined"){
453 }else if(typeof obj[name] == "string"){
454 obj[name] = [obj[name]];
455 obj[name].push(value);
457 obj[name].push(value);
467 * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
468 * passed array is not really an array, your function is called once with it.
469 * The supplied function is called with (Object item, Number index, Array allItems).
470 * @param {Array/NodeList/Mixed} array
471 * @param {Function} fn
472 * @param {Object} scope
474 each : function(array, fn, scope){
475 if(typeof array.length == "undefined" || typeof array == "string"){
478 for(var i = 0, len = array.length; i < len; i++){
479 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
484 combine : function(){
485 var as = arguments, l = as.length, r = [];
486 for(var i = 0; i < l; i++){
488 if(a instanceof Array){
490 }else if(a.length !== undefined && !a.substr){
491 r = r.concat(Array.prototype.slice.call(a, 0));
500 * Escapes the passed string for use in a regular expression
501 * @param {String} str
504 escapeRe : function(s) {
505 return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
509 callback : function(cb, scope, args, delay){
510 if(typeof cb == "function"){
512 cb.defer(delay, scope, args || []);
514 cb.apply(scope, args || []);
520 * Return the dom node for the passed string (id), dom node, or Roo.Element
521 * @param {String/HTMLElement/Roo.Element} el
522 * @return HTMLElement
524 getDom : function(el){
528 return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
532 * Shorthand for {@link Roo.ComponentMgr#get}
534 * @return Roo.Component
536 getCmp : function(id){
537 return Roo.ComponentMgr.get(id);
540 num : function(v, defaultValue){
541 if(typeof v != 'number'){
547 destroy : function(){
548 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
552 as.removeAllListeners();
556 if(typeof as.purgeListeners == 'function'){
559 if(typeof as.destroy == 'function'){
566 // inpired by a similar function in mootools library
568 * Returns the type of object that is passed in. If the object passed in is null or undefined it
569 * return false otherwise it returns one of the following values:<ul>
570 * <li><b>string</b>: If the object passed is a string</li>
571 * <li><b>number</b>: If the object passed is a number</li>
572 * <li><b>boolean</b>: If the object passed is a boolean value</li>
573 * <li><b>function</b>: If the object passed is a function reference</li>
574 * <li><b>object</b>: If the object passed is an object</li>
575 * <li><b>array</b>: If the object passed is an array</li>
576 * <li><b>regexp</b>: If the object passed is a regular expression</li>
577 * <li><b>element</b>: If the object passed is a DOM Element</li>
578 * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
579 * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
580 * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
581 * @param {Mixed} object
585 if(o === undefined || o === null){
592 if(t == 'object' && o.nodeName) {
594 case 1: return 'element';
595 case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
598 if(t == 'object' || t == 'function') {
599 switch(o.constructor) {
600 case Array: return 'array';
601 case RegExp: return 'regexp';
603 if(typeof o.length == 'number' && typeof o.item == 'function') {
611 * Returns true if the passed value is null, undefined or an empty string (optional).
612 * @param {Mixed} value The value to test
613 * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
616 isEmpty : function(v, allowBlank){
617 return v === null || v === undefined || (!allowBlank ? v === '' : false);
625 isFirefox : isFirefox,
637 isBorderBox : isBorderBox,
639 isWindows : isWindows,
647 isAndroid : isAndroid,
652 * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
653 * you may want to set this to true.
656 useShims : ((isIE && !isIE7) || (isGecko && isMac)),
661 * Selects a single element as a Roo Element
662 * This is about as close as you can get to jQuery's $('do crazy stuff')
663 * @param {String} selector The selector/xpath query
664 * @param {Node} root (optional) The start of the query (defaults to document).
665 * @return {Roo.Element}
667 selectNode : function(selector, root)
669 var node = Roo.DomQuery.selectNode(selector,root);
670 return node ? Roo.get(node) : new Roo.Element(false);
673 * Find the current bootstrap width Grid size
674 * Note xs is the default for smaller.. - this is currently used by grids to render correct columns
675 * @returns {String} (xs|sm|md|lg|xl)
678 getGridSize : function()
680 var w = Roo.lib.Dom.getViewWidth();
701 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
702 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout",
705 "Roo.bootstrap.dash");
708 * Ext JS Library 1.1.1
709 * Copyright(c) 2006-2007, Ext JS, LLC.
711 * Originally Released Under LGPL - original licence link has changed is not relivant.
714 * <script type="text/javascript">
718 // wrappedn so fnCleanup is not in global scope...
720 function fnCleanUp() {
721 var p = Function.prototype;
722 delete p.createSequence;
724 delete p.createDelegate;
725 delete p.createCallback;
726 delete p.createInterceptor;
728 window.detachEvent("onunload", fnCleanUp);
730 window.attachEvent("onunload", fnCleanUp);
737 * These functions are available on every Function object (any JavaScript function).
739 Roo.apply(Function.prototype, {
741 * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
742 * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
743 * Will create a function that is bound to those 2 args.
744 * @return {Function} The new function
746 createCallback : function(/*args...*/){
747 // make args available, in function below
748 var args = arguments;
751 return method.apply(window, args);
756 * Creates a delegate (callback) that sets the scope to obj.
757 * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
758 * Will create a function that is automatically scoped to this.
759 * @param {Object} obj (optional) The object for which the scope is set
760 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
761 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
762 * if a number the args are inserted at the specified position
763 * @return {Function} The new function
765 createDelegate : function(obj, args, appendArgs){
768 var callArgs = args || arguments;
769 if(appendArgs === true){
770 callArgs = Array.prototype.slice.call(arguments, 0);
771 callArgs = callArgs.concat(args);
772 }else if(typeof appendArgs == "number"){
773 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
774 var applyArgs = [appendArgs, 0].concat(args); // create method call params
775 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
777 return method.apply(obj || window, callArgs);
782 * Calls this function after the number of millseconds specified.
783 * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
784 * @param {Object} obj (optional) The object for which the scope is set
785 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
786 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
787 * if a number the args are inserted at the specified position
788 * @return {Number} The timeout id that can be used with clearTimeout
790 defer : function(millis, obj, args, appendArgs){
791 var fn = this.createDelegate(obj, args, appendArgs);
793 return setTimeout(fn, millis);
799 * Create a combined function call sequence of the original function + the passed function.
800 * The resulting function returns the results of the original function.
801 * The passed fcn is called with the parameters of the original function
802 * @param {Function} fcn The function to sequence
803 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
804 * @return {Function} The new function
806 createSequence : function(fcn, scope){
807 if(typeof fcn != "function"){
812 var retval = method.apply(this || window, arguments);
813 fcn.apply(scope || this || window, arguments);
819 * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
820 * The resulting function returns the results of the original function.
821 * The passed fcn is called with the parameters of the original function.
823 * @param {Function} fcn The function to call before the original
824 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
825 * @return {Function} The new function
827 createInterceptor : function(fcn, scope){
828 if(typeof fcn != "function"){
835 if(fcn.apply(scope || this || window, arguments) === false){
838 return method.apply(this || window, arguments);
844 * Ext JS Library 1.1.1
845 * Copyright(c) 2006-2007, Ext JS, LLC.
847 * Originally Released Under LGPL - original licence link has changed is not relivant.
850 * <script type="text/javascript">
853 Roo.applyIf(String, {
858 * Escapes the passed string for ' and \
859 * @param {String} string The string to escape
860 * @return {String} The escaped string
863 escape : function(string) {
864 return string.replace(/('|\\)/g, "\\$1");
868 * Pads the left side of a string with a specified character. This is especially useful
869 * for normalizing number and date strings. Example usage:
871 var s = String.leftPad('123', 5, '0');
872 // s now contains the string: '00123'
874 * @param {String} string The original string
875 * @param {Number} size The total length of the output string
876 * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
877 * @return {String} The padded string
880 leftPad : function (val, size, ch) {
881 var result = new String(val);
882 if(ch === null || ch === undefined || ch === '') {
885 while (result.length < size) {
886 result = ch + result;
892 * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens. Each
893 * token must be unique, and must increment in the format {0}, {1}, etc. Example usage:
895 var cls = 'my-class', text = 'Some text';
896 var s = String.format('<div class="{0}">{1}</div>', cls, text);
897 // s now contains the string: '<div class="my-class">Some text</div>'
899 * @param {String} string The tokenized string to be formatted
900 * @param {String} value1 The value to replace token {0}
901 * @param {String} value2 Etc...
902 * @return {String} The formatted string
905 format : function(format){
906 var args = Array.prototype.slice.call(arguments, 1);
907 return format.replace(/\{(\d+)\}/g, function(m, i){
908 return Roo.util.Format.htmlEncode(args[i]);
916 * Utility function that allows you to easily switch a string between two alternating values. The passed value
917 * is compared to the current string, and if they are equal, the other value that was passed in is returned. If
918 * they are already different, the first value passed in is returned. Note that this method returns the new value
919 * but does not change the current string.
921 // alternate sort directions
922 sort = sort.toggle('ASC', 'DESC');
924 // instead of conditional logic:
925 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
927 * @param {String} value The value to compare to the current string
928 * @param {String} other The new value to use if the string already equals the first value passed in
929 * @return {String} The new value
932 String.prototype.toggle = function(value, other){
933 return this == value ? other : value;
938 * Remove invalid unicode characters from a string
940 * @return {String} The clean string
942 String.prototype.unicodeClean = function () {
943 return this.replace(/[\s\S]/g,
944 function(character) {
945 if (character.charCodeAt()< 256) {
949 encodeURIComponent(character);
960 * Ext JS Library 1.1.1
961 * Copyright(c) 2006-2007, Ext JS, LLC.
963 * Originally Released Under LGPL - original licence link has changed is not relivant.
966 * <script type="text/javascript">
972 Roo.applyIf(Number.prototype, {
974 * Checks whether or not the current number is within a desired range. If the number is already within the
975 * range it is returned, otherwise the min or max value is returned depending on which side of the range is
976 * exceeded. Note that this method returns the constrained value but does not change the current number.
977 * @param {Number} min The minimum number in the range
978 * @param {Number} max The maximum number in the range
979 * @return {Number} The constrained value if outside the range, otherwise the current value
981 constrain : function(min, max){
982 return Math.min(Math.max(this, min), max);
986 * Ext JS Library 1.1.1
987 * Copyright(c) 2006-2007, Ext JS, LLC.
989 * Originally Released Under LGPL - original licence link has changed is not relivant.
992 * <script type="text/javascript">
997 Roo.applyIf(Array.prototype, {
1000 * Checks whether or not the specified object exists in the array.
1001 * @param {Object} o The object to check for
1002 * @return {Number} The index of o in the array (or -1 if it is not found)
1004 indexOf : function(o){
1005 for (var i = 0, len = this.length; i < len; i++){
1006 if(this[i] == o) { return i; }
1012 * Removes the specified object from the array. If the object is not found nothing happens.
1013 * @param {Object} o The object to remove
1015 remove : function(o){
1016 var index = this.indexOf(o);
1018 this.splice(index, 1);
1022 * Map (JS 1.6 compatibility)
1023 * @param {Function} function to call
1025 map : function(fun )
1027 var len = this.length >>> 0;
1028 if (typeof fun != "function") {
1029 throw new TypeError();
1031 var res = new Array(len);
1032 var thisp = arguments[1];
1033 for (var i = 0; i < len; i++)
1036 res[i] = fun.call(thisp, this[i], i, this);
1044 * @param {Array} o The array to compare to
1045 * @returns {Boolean} true if the same
1047 equals : function(b)
1049 // https://stackoverflow.com/questions/3115982/how-to-check-if-two-arrays-are-equal-with-javascript
1056 if (this.length !== b.length) {
1060 // sort?? a.sort().equals(b.sort());
1062 for (var i = 0; i < this.length; ++i) {
1063 if (this[i] !== b[i]) {
1075 Roo.applyIf(Array, {
1079 * @param {Array} o Or Array like object (eg. nodelist)
1086 for (var i =0; i < o.length; i++) {
1095 * Ext JS Library 1.1.1
1096 * Copyright(c) 2006-2007, Ext JS, LLC.
1098 * Originally Released Under LGPL - original licence link has changed is not relivant.
1101 * <script type="text/javascript">
1107 * The date parsing and format syntax is a subset of
1108 * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
1109 * supported will provide results equivalent to their PHP versions.
1111 * Following is the list of all currently supported formats:
1114 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
1116 Format Output Description
1117 ------ ---------- --------------------------------------------------------------
1118 d 10 Day of the month, 2 digits with leading zeros
1119 D Wed A textual representation of a day, three letters
1120 j 10 Day of the month without leading zeros
1121 l Wednesday A full textual representation of the day of the week
1122 S th English ordinal day of month suffix, 2 chars (use with j)
1123 w 3 Numeric representation of the day of the week
1124 z 9 The julian date, or day of the year (0-365)
1125 W 01 ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
1126 F January A full textual representation of the month
1127 m 01 Numeric representation of a month, with leading zeros
1128 M Jan Month name abbreviation, three letters
1129 n 1 Numeric representation of a month, without leading zeros
1130 t 31 Number of days in the given month
1131 L 0 Whether it's a leap year (1 if it is a leap year, else 0)
1132 Y 2007 A full numeric representation of a year, 4 digits
1133 y 07 A two digit representation of a year
1134 a pm Lowercase Ante meridiem and Post meridiem
1135 A PM Uppercase Ante meridiem and Post meridiem
1136 g 3 12-hour format of an hour without leading zeros
1137 G 15 24-hour format of an hour without leading zeros
1138 h 03 12-hour format of an hour with leading zeros
1139 H 15 24-hour format of an hour with leading zeros
1140 i 05 Minutes with leading zeros
1141 s 01 Seconds, with leading zeros
1142 O -0600 Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1143 P -06:00 Difference to Greenwich time (GMT) with colon between hours and minutes
1144 T CST Timezone setting of the machine running the code
1145 Z -21600 Timezone offset in seconds (negative if west of UTC, positive if east)
1148 * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1150 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1151 document.write(dt.format('Y-m-d')); //2007-01-10
1152 document.write(dt.format('F j, Y, g:i a')); //January 10, 2007, 3:05 pm
1153 document.write(dt.format('l, \\t\\he dS of F Y h:i:s A')); //Wednesday, the 10th of January 2007 03:05:01 PM
1156 * Here are some standard date/time patterns that you might find helpful. They
1157 * are not part of the source of Date.js, but to use them you can simply copy this
1158 * block of code into any script that is included after Date.js and they will also become
1159 * globally available on the Date object. Feel free to add or remove patterns as needed in your code.
1162 ISO8601Long:"Y-m-d H:i:s",
1163 ISO8601Short:"Y-m-d",
1165 LongDate: "l, F d, Y",
1166 FullDateTime: "l, F d, Y g:i:s A",
1169 LongTime: "g:i:s A",
1170 SortableDateTime: "Y-m-d\\TH:i:s",
1171 UniversalSortableDateTime: "Y-m-d H:i:sO",
1178 var dt = new Date();
1179 document.write(dt.format(Date.patterns.ShortDate));
1184 * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1185 * They generate precompiled functions from date formats instead of parsing and
1186 * processing the pattern every time you format a date. These functions are available
1187 * on every Date object (any javascript function).
1189 * The original article and download are here:
1190 * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1197 Returns the number of milliseconds between this date and date
1198 @param {Date} date (optional) Defaults to now
1199 @return {Number} The diff in milliseconds
1200 @member Date getElapsed
1202 Date.prototype.getElapsed = function(date) {
1203 return Math.abs((date || new Date()).getTime()-this.getTime());
1205 // was in date file..
1209 Date.parseFunctions = {count:0};
1211 Date.parseRegexes = [];
1213 Date.formatFunctions = {count:0};
1216 Date.prototype.dateFormat = function(format) {
1217 if (Date.formatFunctions[format] == null) {
1218 Date.createNewFormat(format);
1220 var func = Date.formatFunctions[format];
1221 return this[func]();
1226 * Formats a date given the supplied format string
1227 * @param {String} format The format string
1228 * @return {String} The formatted date
1231 Date.prototype.format = Date.prototype.dateFormat;
1234 Date.createNewFormat = function(format) {
1235 var funcName = "format" + Date.formatFunctions.count++;
1236 Date.formatFunctions[format] = funcName;
1237 var code = "Date.prototype." + funcName + " = function(){return ";
1238 var special = false;
1240 for (var i = 0; i < format.length; ++i) {
1241 ch = format.charAt(i);
1242 if (!special && ch == "\\") {
1247 code += "'" + String.escape(ch) + "' + ";
1250 code += Date.getFormatCode(ch);
1253 /** eval:var:zzzzzzzzzzzzz */
1254 eval(code.substring(0, code.length - 3) + ";}");
1258 Date.getFormatCode = function(character) {
1259 switch (character) {
1261 return "String.leftPad(this.getDate(), 2, '0') + ";
1263 return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1265 return "this.getDate() + ";
1267 return "Date.dayNames[this.getDay()] + ";
1269 return "this.getSuffix() + ";
1271 return "this.getDay() + ";
1273 return "this.getDayOfYear() + ";
1275 return "this.getWeekOfYear() + ";
1277 return "Date.monthNames[this.getMonth()] + ";
1279 return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1281 return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1283 return "(this.getMonth() + 1) + ";
1285 return "this.getDaysInMonth() + ";
1287 return "(this.isLeapYear() ? 1 : 0) + ";
1289 return "this.getFullYear() + ";
1291 return "('' + this.getFullYear()).substring(2, 4) + ";
1293 return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1295 return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1297 return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1299 return "this.getHours() + ";
1301 return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1303 return "String.leftPad(this.getHours(), 2, '0') + ";
1305 return "String.leftPad(this.getMinutes(), 2, '0') + ";
1307 return "String.leftPad(this.getSeconds(), 2, '0') + ";
1309 return "this.getGMTOffset() + ";
1311 return "this.getGMTColonOffset() + ";
1313 return "this.getTimezone() + ";
1315 return "(this.getTimezoneOffset() * -60) + ";
1317 return "'" + String.escape(character) + "' + ";
1322 * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1323 * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates. Any part of
1324 * the date format that is not specified will default to the current date value for that part. Time parts can also
1325 * be specified, but default to 0. Keep in mind that the input date string must precisely match the specified format
1326 * string or the parse operation will fail.
1329 //dt = Fri May 25 2007 (current date)
1330 var dt = new Date();
1332 //dt = Thu May 25 2006 (today's month/day in 2006)
1333 dt = Date.parseDate("2006", "Y");
1335 //dt = Sun Jan 15 2006 (all date parts specified)
1336 dt = Date.parseDate("2006-1-15", "Y-m-d");
1338 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1339 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1341 * @param {String} input The unparsed date as a string
1342 * @param {String} format The format the date is in
1343 * @return {Date} The parsed date
1346 Date.parseDate = function(input, format) {
1347 if (Date.parseFunctions[format] == null) {
1348 Date.createParser(format);
1350 var func = Date.parseFunctions[format];
1351 return Date[func](input);
1357 Date.createParser = function(format) {
1358 var funcName = "parse" + Date.parseFunctions.count++;
1359 var regexNum = Date.parseRegexes.length;
1360 var currentGroup = 1;
1361 Date.parseFunctions[format] = funcName;
1363 var code = "Date." + funcName + " = function(input){\n"
1364 + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1365 + "var d = new Date();\n"
1366 + "y = d.getFullYear();\n"
1367 + "m = d.getMonth();\n"
1368 + "d = d.getDate();\n"
1369 + "if (typeof(input) !== 'string') { input = input.toString(); }\n"
1370 + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1371 + "if (results && results.length > 0) {";
1374 var special = false;
1376 for (var i = 0; i < format.length; ++i) {
1377 ch = format.charAt(i);
1378 if (!special && ch == "\\") {
1383 regex += String.escape(ch);
1386 var obj = Date.formatCodeToRegex(ch, currentGroup);
1387 currentGroup += obj.g;
1389 if (obj.g && obj.c) {
1395 code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1396 + "{v = new Date(y, m, d, h, i, s);}\n"
1397 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1398 + "{v = new Date(y, m, d, h, i);}\n"
1399 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1400 + "{v = new Date(y, m, d, h);}\n"
1401 + "else if (y >= 0 && m >= 0 && d > 0)\n"
1402 + "{v = new Date(y, m, d);}\n"
1403 + "else if (y >= 0 && m >= 0)\n"
1404 + "{v = new Date(y, m);}\n"
1405 + "else if (y >= 0)\n"
1406 + "{v = new Date(y);}\n"
1407 + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1408 + " ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1409 + " v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1412 Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1413 /** eval:var:zzzzzzzzzzzzz */
1418 Date.formatCodeToRegex = function(character, currentGroup) {
1419 switch (character) {
1423 s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1426 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1427 s:"(\\d{1,2})"}; // day of month without leading zeroes
1430 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1431 s:"(\\d{2})"}; // day of month with leading zeroes
1435 s:"(?:" + Date.dayNames.join("|") + ")"};
1439 s:"(?:st|nd|rd|th)"};
1454 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1455 s:"(" + Date.monthNames.join("|") + ")"};
1458 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1459 s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1462 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1463 s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1466 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1467 s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1478 c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1482 c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1483 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1487 c:"if (results[" + currentGroup + "] == 'am') {\n"
1488 + "if (h == 12) { h = 0; }\n"
1489 + "} else { if (h < 12) { h += 12; }}",
1493 c:"if (results[" + currentGroup + "] == 'AM') {\n"
1494 + "if (h == 12) { h = 0; }\n"
1495 + "} else { if (h < 12) { h += 12; }}",
1500 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1501 s:"(\\d{1,2})"}; // 12/24-hr format format of an hour without leading zeroes
1505 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1506 s:"(\\d{2})"}; // 12/24-hr format format of an hour with leading zeroes
1509 c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1513 c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1518 "o = results[", currentGroup, "];\n",
1519 "var sn = o.substring(0,1);\n", // get + / - sign
1520 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1521 "var mn = o.substring(3,5) % 60;\n", // get minutes
1522 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1523 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1525 s:"([+\-]\\d{2,4})"};
1531 "o = results[", currentGroup, "];\n",
1532 "var sn = o.substring(0,1);\n",
1533 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1534 "var mn = o.substring(4,6) % 60;\n",
1535 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1536 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1542 s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1545 c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1546 + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1547 s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1551 s:String.escape(character)};
1556 * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1557 * @return {String} The abbreviated timezone name (e.g. 'CST')
1559 Date.prototype.getTimezone = function() {
1560 return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1564 * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1565 * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1567 Date.prototype.getGMTOffset = function() {
1568 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1569 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1570 + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1574 * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1575 * @return {String} 2-characters representing hours and 2-characters representing minutes
1576 * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1578 Date.prototype.getGMTColonOffset = function() {
1579 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1580 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1582 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1586 * Get the numeric day number of the year, adjusted for leap year.
1587 * @return {Number} 0 through 364 (365 in leap years)
1589 Date.prototype.getDayOfYear = function() {
1591 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1592 for (var i = 0; i < this.getMonth(); ++i) {
1593 num += Date.daysInMonth[i];
1595 return num + this.getDate() - 1;
1599 * Get the string representation of the numeric week number of the year
1600 * (equivalent to the format specifier 'W').
1601 * @return {String} '00' through '52'
1603 Date.prototype.getWeekOfYear = function() {
1604 // Skip to Thursday of this week
1605 var now = this.getDayOfYear() + (4 - this.getDay());
1606 // Find the first Thursday of the year
1607 var jan1 = new Date(this.getFullYear(), 0, 1);
1608 var then = (7 - jan1.getDay() + 4);
1609 return String.leftPad(((now - then) / 7) + 1, 2, "0");
1613 * Whether or not the current date is in a leap year.
1614 * @return {Boolean} True if the current date is in a leap year, else false
1616 Date.prototype.isLeapYear = function() {
1617 var year = this.getFullYear();
1618 return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1622 * Get the first day of the current month, adjusted for leap year. The returned value
1623 * is the numeric day index within the week (0-6) which can be used in conjunction with
1624 * the {@link #monthNames} array to retrieve the textual day name.
1627 var dt = new Date('1/10/2007');
1628 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1630 * @return {Number} The day number (0-6)
1632 Date.prototype.getFirstDayOfMonth = function() {
1633 var day = (this.getDay() - (this.getDate() - 1)) % 7;
1634 return (day < 0) ? (day + 7) : day;
1638 * Get the last day of the current month, adjusted for leap year. The returned value
1639 * is the numeric day index within the week (0-6) which can be used in conjunction with
1640 * the {@link #monthNames} array to retrieve the textual day name.
1643 var dt = new Date('1/10/2007');
1644 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1646 * @return {Number} The day number (0-6)
1648 Date.prototype.getLastDayOfMonth = function() {
1649 var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1650 return (day < 0) ? (day + 7) : day;
1655 * Get the first date of this date's month
1658 Date.prototype.getFirstDateOfMonth = function() {
1659 return new Date(this.getFullYear(), this.getMonth(), 1);
1663 * Get the last date of this date's month
1666 Date.prototype.getLastDateOfMonth = function() {
1667 return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1670 * Get the number of days in the current month, adjusted for leap year.
1671 * @return {Number} The number of days in the month
1673 Date.prototype.getDaysInMonth = function() {
1674 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1675 return Date.daysInMonth[this.getMonth()];
1679 * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1680 * @return {String} 'st, 'nd', 'rd' or 'th'
1682 Date.prototype.getSuffix = function() {
1683 switch (this.getDate()) {
1700 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1703 * An array of textual month names.
1704 * Override these values for international dates, for example...
1705 * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1724 * An array of textual day names.
1725 * Override these values for international dates, for example...
1726 * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1742 Date.monthNumbers = {
1757 * Creates and returns a new Date instance with the exact same date value as the called instance.
1758 * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1759 * variable will also be changed. When the intention is to create a new variable that will not
1760 * modify the original instance, you should create a clone.
1762 * Example of correctly cloning a date:
1765 var orig = new Date('10/1/2006');
1768 document.write(orig); //returns 'Thu Oct 05 2006'!
1771 var orig = new Date('10/1/2006');
1772 var copy = orig.clone();
1774 document.write(orig); //returns 'Thu Oct 01 2006'
1776 * @return {Date} The new Date instance
1778 Date.prototype.clone = function() {
1779 return new Date(this.getTime());
1783 * Clears any time information from this date
1784 @param {Boolean} clone true to create a clone of this date, clear the time and return it
1785 @return {Date} this or the clone
1787 Date.prototype.clearTime = function(clone){
1789 return this.clone().clearTime();
1794 this.setMilliseconds(0);
1799 // safari setMonth is broken -- check that this is only donw once...
1800 if(Roo.isSafari && typeof(Date.brokenSetMonth) == 'undefined'){
1801 Date.brokenSetMonth = Date.prototype.setMonth;
1802 Date.prototype.setMonth = function(num){
1804 var n = Math.ceil(-num);
1805 var back_year = Math.ceil(n/12);
1806 var month = (n % 12) ? 12 - n % 12 : 0 ;
1807 this.setFullYear(this.getFullYear() - back_year);
1808 return Date.brokenSetMonth.call(this, month);
1810 return Date.brokenSetMonth.apply(this, arguments);
1815 /** Date interval constant
1819 /** Date interval constant
1823 /** Date interval constant
1827 /** Date interval constant
1831 /** Date interval constant
1835 /** Date interval constant
1839 /** Date interval constant
1845 * Provides a convenient method of performing basic date arithmetic. This method
1846 * does not modify the Date instance being called - it creates and returns
1847 * a new Date instance containing the resulting date value.
1852 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1853 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1855 //Negative values will subtract correctly:
1856 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1857 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1859 //You can even chain several calls together in one line!
1860 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1861 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1864 * @param {String} interval A valid date interval enum value
1865 * @param {Number} value The amount to add to the current date
1866 * @return {Date} The new Date instance
1868 Date.prototype.add = function(interval, value){
1869 var d = this.clone();
1870 if (!interval || value === 0) { return d; }
1871 switch(interval.toLowerCase()){
1873 d.setMilliseconds(this.getMilliseconds() + value);
1876 d.setSeconds(this.getSeconds() + value);
1879 d.setMinutes(this.getMinutes() + value);
1882 d.setHours(this.getHours() + value);
1885 d.setDate(this.getDate() + value);
1888 var day = this.getDate();
1890 day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1893 d.setMonth(this.getMonth() + value);
1896 d.setFullYear(this.getFullYear() + value);
1902 * @class Roo.lib.Dom
1906 * Dom utils (from YIU afaik)
1912 * Get the view width
1913 * @param {Boolean} full True will get the full document, otherwise it's the view width
1914 * @return {Number} The width
1917 getViewWidth : function(full) {
1918 return full ? this.getDocumentWidth() : this.getViewportWidth();
1921 * Get the view height
1922 * @param {Boolean} full True will get the full document, otherwise it's the view height
1923 * @return {Number} The height
1925 getViewHeight : function(full) {
1926 return full ? this.getDocumentHeight() : this.getViewportHeight();
1929 * Get the Full Document height
1930 * @return {Number} The height
1932 getDocumentHeight: function() {
1933 var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1934 return Math.max(scrollHeight, this.getViewportHeight());
1937 * Get the Full Document width
1938 * @return {Number} The width
1940 getDocumentWidth: function() {
1941 var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1942 return Math.max(scrollWidth, this.getViewportWidth());
1945 * Get the Window Viewport height
1946 * @return {Number} The height
1948 getViewportHeight: function() {
1949 var height = self.innerHeight;
1950 var mode = document.compatMode;
1952 if ((mode || Roo.isIE) && !Roo.isOpera) {
1953 height = (mode == "CSS1Compat") ?
1954 document.documentElement.clientHeight :
1955 document.body.clientHeight;
1961 * Get the Window Viewport width
1962 * @return {Number} The width
1964 getViewportWidth: function() {
1965 var width = self.innerWidth;
1966 var mode = document.compatMode;
1968 if (mode || Roo.isIE) {
1969 width = (mode == "CSS1Compat") ?
1970 document.documentElement.clientWidth :
1971 document.body.clientWidth;
1976 isAncestor : function(p, c) {
1983 if (p.contains && !Roo.isSafari) {
1984 return p.contains(c);
1985 } else if (p.compareDocumentPosition) {
1986 return !!(p.compareDocumentPosition(c) & 16);
1988 var parent = c.parentNode;
1993 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1996 parent = parent.parentNode;
2002 getRegion : function(el) {
2003 return Roo.lib.Region.getRegion(el);
2006 getY : function(el) {
2007 return this.getXY(el)[1];
2010 getX : function(el) {
2011 return this.getXY(el)[0];
2014 getXY : function(el) {
2015 var p, pe, b, scroll, bd = document.body;
2016 el = Roo.getDom(el);
2017 var fly = Roo.lib.AnimBase.fly;
2018 if (el.getBoundingClientRect) {
2019 b = el.getBoundingClientRect();
2020 scroll = fly(document).getScroll();
2021 return [b.left + scroll.left, b.top + scroll.top];
2027 var hasAbsolute = fly(el).getStyle("position") == "absolute";
2034 if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
2041 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
2042 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
2049 if (p != el && pe.getStyle('overflow') != 'visible') {
2057 if (Roo.isSafari && hasAbsolute) {
2062 if (Roo.isGecko && !hasAbsolute) {
2064 x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
2065 y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
2069 while (p && p != bd) {
2070 if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
2082 setXY : function(el, xy) {
2083 el = Roo.fly(el, '_setXY');
2085 var pts = el.translatePoints(xy);
2086 if (xy[0] !== false) {
2087 el.dom.style.left = pts.left + "px";
2089 if (xy[1] !== false) {
2090 el.dom.style.top = pts.top + "px";
2094 setX : function(el, x) {
2095 this.setXY(el, [x, false]);
2098 setY : function(el, y) {
2099 this.setXY(el, [false, y]);
2103 * Portions of this file are based on pieces of Yahoo User Interface Library
2104 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2105 * YUI licensed under the BSD License:
2106 * http://developer.yahoo.net/yui/license.txt
2107 * <script type="text/javascript">
2111 Roo.lib.Event = function() {
2112 var loadComplete = false;
2114 var unloadListeners = [];
2116 var onAvailStack = [];
2118 var lastError = null;
2131 startInterval: function() {
2132 if (!this._interval) {
2134 var callback = function() {
2135 self._tryPreloadAttach();
2137 this._interval = setInterval(callback, this.POLL_INTERVAL);
2142 onAvailable: function(p_id, p_fn, p_obj, p_override) {
2143 onAvailStack.push({ id: p_id,
2146 override: p_override,
2147 checkReady: false });
2149 retryCount = this.POLL_RETRYS;
2150 this.startInterval();
2154 addListener: function(el, eventName, fn) {
2155 el = Roo.getDom(el);
2160 if ("unload" == eventName) {
2161 unloadListeners[unloadListeners.length] =
2162 [el, eventName, fn];
2166 var wrappedFn = function(e) {
2167 return fn(Roo.lib.Event.getEvent(e));
2170 var li = [el, eventName, fn, wrappedFn];
2172 var index = listeners.length;
2173 listeners[index] = li;
2175 this.doAdd(el, eventName, wrappedFn, false);
2181 removeListener: function(el, eventName, fn) {
2184 el = Roo.getDom(el);
2187 return this.purgeElement(el, false, eventName);
2191 if ("unload" == eventName) {
2193 for (i = 0,len = unloadListeners.length; i < len; i++) {
2194 var li = unloadListeners[i];
2197 li[1] == eventName &&
2199 unloadListeners.splice(i, 1);
2207 var cacheItem = null;
2210 var index = arguments[3];
2212 if ("undefined" == typeof index) {
2213 index = this._getCacheIndex(el, eventName, fn);
2217 cacheItem = listeners[index];
2220 if (!el || !cacheItem) {
2224 this.doRemove(el, eventName, cacheItem[this.WFN], false);
2226 delete listeners[index][this.WFN];
2227 delete listeners[index][this.FN];
2228 listeners.splice(index, 1);
2235 getTarget: function(ev, resolveTextNode) {
2236 ev = ev.browserEvent || ev;
2237 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2238 var t = ev.target || ev.srcElement;
2239 return this.resolveTextNode(t);
2243 resolveTextNode: function(node) {
2244 if (Roo.isSafari && node && 3 == node.nodeType) {
2245 return node.parentNode;
2252 getPageX: function(ev) {
2253 ev = ev.browserEvent || ev;
2254 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2256 if (!x && 0 !== x) {
2257 x = ev.clientX || 0;
2260 x += this.getScroll()[1];
2268 getPageY: function(ev) {
2269 ev = ev.browserEvent || ev;
2270 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2272 if (!y && 0 !== y) {
2273 y = ev.clientY || 0;
2276 y += this.getScroll()[0];
2285 getXY: function(ev) {
2286 ev = ev.browserEvent || ev;
2287 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2288 return [this.getPageX(ev), this.getPageY(ev)];
2292 getRelatedTarget: function(ev) {
2293 ev = ev.browserEvent || ev;
2294 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2295 var t = ev.relatedTarget;
2297 if (ev.type == "mouseout") {
2299 } else if (ev.type == "mouseover") {
2304 return this.resolveTextNode(t);
2308 getTime: function(ev) {
2309 ev = ev.browserEvent || ev;
2310 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2312 var t = new Date().getTime();
2316 this.lastError = ex;
2325 stopEvent: function(ev) {
2326 this.stopPropagation(ev);
2327 this.preventDefault(ev);
2331 stopPropagation: function(ev) {
2332 ev = ev.browserEvent || ev;
2333 if (ev.stopPropagation) {
2334 ev.stopPropagation();
2336 ev.cancelBubble = true;
2341 preventDefault: function(ev) {
2342 ev = ev.browserEvent || ev;
2343 if(ev.preventDefault) {
2344 ev.preventDefault();
2346 ev.returnValue = false;
2351 getEvent: function(e) {
2352 var ev = e || window.event;
2354 var c = this.getEvent.caller;
2356 ev = c.arguments[0];
2357 if (ev && Event == ev.constructor) {
2367 getCharCode: function(ev) {
2368 ev = ev.browserEvent || ev;
2369 return ev.charCode || ev.keyCode || 0;
2373 _getCacheIndex: function(el, eventName, fn) {
2374 for (var i = 0,len = listeners.length; i < len; ++i) {
2375 var li = listeners[i];
2377 li[this.FN] == fn &&
2378 li[this.EL] == el &&
2379 li[this.TYPE] == eventName) {
2391 getEl: function(id) {
2392 return document.getElementById(id);
2396 clearCache: function() {
2400 _load: function(e) {
2401 loadComplete = true;
2402 var EU = Roo.lib.Event;
2406 EU.doRemove(window, "load", EU._load);
2411 _tryPreloadAttach: function() {
2420 var tryAgain = !loadComplete;
2422 tryAgain = (retryCount > 0);
2427 for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2428 var item = onAvailStack[i];
2430 var el = this.getEl(item.id);
2433 if (!item.checkReady ||
2436 (document && document.body)) {
2439 if (item.override) {
2440 if (item.override === true) {
2443 scope = item.override;
2446 item.fn.call(scope, item.obj);
2447 onAvailStack[i] = null;
2450 notAvail.push(item);
2455 retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2459 this.startInterval();
2461 clearInterval(this._interval);
2462 this._interval = null;
2465 this.locked = false;
2472 purgeElement: function(el, recurse, eventName) {
2473 var elListeners = this.getListeners(el, eventName);
2475 for (var i = 0,len = elListeners.length; i < len; ++i) {
2476 var l = elListeners[i];
2477 this.removeListener(el, l.type, l.fn);
2481 if (recurse && el && el.childNodes) {
2482 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2483 this.purgeElement(el.childNodes[i], recurse, eventName);
2489 getListeners: function(el, eventName) {
2490 var results = [], searchLists;
2492 searchLists = [listeners, unloadListeners];
2493 } else if (eventName == "unload") {
2494 searchLists = [unloadListeners];
2496 searchLists = [listeners];
2499 for (var j = 0; j < searchLists.length; ++j) {
2500 var searchList = searchLists[j];
2501 if (searchList && searchList.length > 0) {
2502 for (var i = 0,len = searchList.length; i < len; ++i) {
2503 var l = searchList[i];
2504 if (l && l[this.EL] === el &&
2505 (!eventName || eventName === l[this.TYPE])) {
2510 adjust: l[this.ADJ_SCOPE],
2518 return (results.length) ? results : null;
2522 _unload: function(e) {
2524 var EU = Roo.lib.Event, i, j, l, len, index;
2526 for (i = 0,len = unloadListeners.length; i < len; ++i) {
2527 l = unloadListeners[i];
2530 if (l[EU.ADJ_SCOPE]) {
2531 if (l[EU.ADJ_SCOPE] === true) {
2534 scope = l[EU.ADJ_SCOPE];
2537 l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2538 unloadListeners[i] = null;
2544 unloadListeners = null;
2546 if (listeners && listeners.length > 0) {
2547 j = listeners.length;
2550 l = listeners[index];
2552 EU.removeListener(l[EU.EL], l[EU.TYPE],
2562 EU.doRemove(window, "unload", EU._unload);
2567 getScroll: function() {
2568 var dd = document.documentElement, db = document.body;
2569 if (dd && (dd.scrollTop || dd.scrollLeft)) {
2570 return [dd.scrollTop, dd.scrollLeft];
2572 return [db.scrollTop, db.scrollLeft];
2579 doAdd: function () {
2580 if (window.addEventListener) {
2581 return function(el, eventName, fn, capture) {
2582 el.addEventListener(eventName, fn, (capture));
2584 } else if (window.attachEvent) {
2585 return function(el, eventName, fn, capture) {
2586 el.attachEvent("on" + eventName, fn);
2595 doRemove: function() {
2596 if (window.removeEventListener) {
2597 return function (el, eventName, fn, capture) {
2598 el.removeEventListener(eventName, fn, (capture));
2600 } else if (window.detachEvent) {
2601 return function (el, eventName, fn) {
2602 el.detachEvent("on" + eventName, fn);
2614 var E = Roo.lib.Event;
2615 E.on = E.addListener;
2616 E.un = E.removeListener;
2618 if (document && document.body) {
2621 E.doAdd(window, "load", E._load);
2623 E.doAdd(window, "unload", E._unload);
2624 E._tryPreloadAttach();
2631 * @class Roo.lib.Ajax
2633 * provide a simple Ajax request utility functions
2635 * Portions of this file are based on pieces of Yahoo User Interface Library
2636 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2637 * YUI licensed under the BSD License:
2638 * http://developer.yahoo.net/yui/license.txt
2639 * <script type="text/javascript">
2647 request : function(method, uri, cb, data, options) {
2649 var hs = options.headers;
2652 if(hs.hasOwnProperty(h)){
2653 this.initHeader(h, hs[h], false);
2657 if(options.xmlData){
2658 this.initHeader('Content-Type', 'text/xml', false);
2660 data = options.xmlData;
2664 return this.asyncRequest(method, uri, cb, data);
2670 * @param {DomForm} form element
2671 * @return {String} urlencode form output.
2673 serializeForm : function(form) {
2674 if(typeof form == 'string') {
2675 form = (document.getElementById(form) || document.forms[form]);
2678 var el, name, val, disabled, data = '', hasSubmit = false;
2679 for (var i = 0; i < form.elements.length; i++) {
2680 el = form.elements[i];
2681 disabled = form.elements[i].disabled;
2682 name = form.elements[i].name;
2683 val = form.elements[i].value;
2685 if (!disabled && name){
2689 case 'select-multiple':
2690 for (var j = 0; j < el.options.length; j++) {
2691 if (el.options[j].selected) {
2693 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2696 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2704 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2717 if(hasSubmit == false) {
2718 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2723 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2728 data = data.substr(0, data.length - 1);
2736 useDefaultHeader:true,
2738 defaultPostHeader:'application/x-www-form-urlencoded',
2740 useDefaultXhrHeader:true,
2742 defaultXhrHeader:'XMLHttpRequest',
2744 hasDefaultHeaders:true,
2756 setProgId:function(id)
2758 this.activeX.unshift(id);
2761 setDefaultPostHeader:function(b)
2763 this.useDefaultHeader = b;
2766 setDefaultXhrHeader:function(b)
2768 this.useDefaultXhrHeader = b;
2771 setPollingInterval:function(i)
2773 if (typeof i == 'number' && isFinite(i)) {
2774 this.pollInterval = i;
2778 createXhrObject:function(transactionId)
2784 http = new XMLHttpRequest();
2786 obj = { conn:http, tId:transactionId };
2790 for (var i = 0; i < this.activeX.length; ++i) {
2794 http = new ActiveXObject(this.activeX[i]);
2796 obj = { conn:http, tId:transactionId };
2809 getConnectionObject:function()
2812 var tId = this.transactionId;
2816 o = this.createXhrObject(tId);
2818 this.transactionId++;
2829 asyncRequest:function(method, uri, callback, postData)
2831 var o = this.getConnectionObject();
2837 o.conn.open(method, uri, true);
2839 if (this.useDefaultXhrHeader) {
2840 if (!this.defaultHeaders['X-Requested-With']) {
2841 this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2845 if(postData && this.useDefaultHeader){
2846 this.initHeader('Content-Type', this.defaultPostHeader);
2849 if (this.hasDefaultHeaders || this.hasHeaders) {
2853 this.handleReadyState(o, callback);
2854 o.conn.send(postData || null);
2860 handleReadyState:function(o, callback)
2864 if (callback && callback.timeout) {
2866 this.timeout[o.tId] = window.setTimeout(function() {
2867 oConn.abort(o, callback, true);
2868 }, callback.timeout);
2871 this.poll[o.tId] = window.setInterval(
2873 if (o.conn && o.conn.readyState == 4) {
2874 window.clearInterval(oConn.poll[o.tId]);
2875 delete oConn.poll[o.tId];
2877 if(callback && callback.timeout) {
2878 window.clearTimeout(oConn.timeout[o.tId]);
2879 delete oConn.timeout[o.tId];
2882 oConn.handleTransactionResponse(o, callback);
2885 , this.pollInterval);
2888 handleTransactionResponse:function(o, callback, isAbort)
2892 this.releaseObject(o);
2896 var httpStatus, responseObject;
2900 if (o.conn.status !== undefined && o.conn.status != 0) {
2901 httpStatus = o.conn.status;
2913 if (httpStatus >= 200 && httpStatus < 300) {
2914 responseObject = this.createResponseObject(o, callback.argument);
2915 if (callback.success) {
2916 if (!callback.scope) {
2917 callback.success(responseObject);
2922 callback.success.apply(callback.scope, [responseObject]);
2927 switch (httpStatus) {
2935 responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2936 if (callback.failure) {
2937 if (!callback.scope) {
2938 callback.failure(responseObject);
2941 callback.failure.apply(callback.scope, [responseObject]);
2946 responseObject = this.createResponseObject(o, callback.argument);
2947 if (callback.failure) {
2948 if (!callback.scope) {
2949 callback.failure(responseObject);
2952 callback.failure.apply(callback.scope, [responseObject]);
2958 this.releaseObject(o);
2959 responseObject = null;
2962 createResponseObject:function(o, callbackArg)
2969 var headerStr = o.conn.getAllResponseHeaders();
2970 var header = headerStr.split('\n');
2971 for (var i = 0; i < header.length; i++) {
2972 var delimitPos = header[i].indexOf(':');
2973 if (delimitPos != -1) {
2974 headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2982 obj.status = o.conn.status;
2983 obj.statusText = o.conn.statusText;
2984 obj.getResponseHeader = headerObj;
2985 obj.getAllResponseHeaders = headerStr;
2986 obj.responseText = o.conn.responseText;
2987 obj.responseXML = o.conn.responseXML;
2989 if (typeof callbackArg !== undefined) {
2990 obj.argument = callbackArg;
2996 createExceptionObject:function(tId, callbackArg, isAbort)
2999 var COMM_ERROR = 'communication failure';
3000 var ABORT_CODE = -1;
3001 var ABORT_ERROR = 'transaction aborted';
3007 obj.status = ABORT_CODE;
3008 obj.statusText = ABORT_ERROR;
3011 obj.status = COMM_CODE;
3012 obj.statusText = COMM_ERROR;
3016 obj.argument = callbackArg;
3022 initHeader:function(label, value, isDefault)
3024 var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
3026 if (headerObj[label] === undefined) {
3027 headerObj[label] = value;
3032 headerObj[label] = value + "," + headerObj[label];
3036 this.hasDefaultHeaders = true;
3039 this.hasHeaders = true;
3044 setHeader:function(o)
3046 if (this.hasDefaultHeaders) {
3047 for (var prop in this.defaultHeaders) {
3048 if (this.defaultHeaders.hasOwnProperty(prop)) {
3049 o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
3054 if (this.hasHeaders) {
3055 for (var prop in this.headers) {
3056 if (this.headers.hasOwnProperty(prop)) {
3057 o.conn.setRequestHeader(prop, this.headers[prop]);
3061 this.hasHeaders = false;
3065 resetDefaultHeaders:function() {
3066 delete this.defaultHeaders;
3067 this.defaultHeaders = {};
3068 this.hasDefaultHeaders = false;
3071 abort:function(o, callback, isTimeout)
3073 if(this.isCallInProgress(o)) {
3075 window.clearInterval(this.poll[o.tId]);
3076 delete this.poll[o.tId];
3078 delete this.timeout[o.tId];
3081 this.handleTransactionResponse(o, callback, true);
3091 isCallInProgress:function(o)
3094 return o.conn.readyState != 4 && o.conn.readyState != 0;
3103 releaseObject:function(o)
3112 'MSXML2.XMLHTTP.3.0',
3120 * Portions of this file are based on pieces of Yahoo User Interface Library
3121 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3122 * YUI licensed under the BSD License:
3123 * http://developer.yahoo.net/yui/license.txt
3124 * <script type="text/javascript">
3128 Roo.lib.Region = function(t, r, b, l) {
3138 Roo.lib.Region.prototype = {
3139 contains : function(region) {
3140 return ( region.left >= this.left &&
3141 region.right <= this.right &&
3142 region.top >= this.top &&
3143 region.bottom <= this.bottom );
3147 getArea : function() {
3148 return ( (this.bottom - this.top) * (this.right - this.left) );
3151 intersect : function(region) {
3152 var t = Math.max(this.top, region.top);
3153 var r = Math.min(this.right, region.right);
3154 var b = Math.min(this.bottom, region.bottom);
3155 var l = Math.max(this.left, region.left);
3157 if (b >= t && r >= l) {
3158 return new Roo.lib.Region(t, r, b, l);
3163 union : function(region) {
3164 var t = Math.min(this.top, region.top);
3165 var r = Math.max(this.right, region.right);
3166 var b = Math.max(this.bottom, region.bottom);
3167 var l = Math.min(this.left, region.left);
3169 return new Roo.lib.Region(t, r, b, l);
3172 adjust : function(t, l, b, r) {
3181 Roo.lib.Region.getRegion = function(el) {
3182 var p = Roo.lib.Dom.getXY(el);
3185 var r = p[0] + el.offsetWidth;
3186 var b = p[1] + el.offsetHeight;
3189 return new Roo.lib.Region(t, r, b, l);
3192 * Portions of this file are based on pieces of Yahoo User Interface Library
3193 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3194 * YUI licensed under the BSD License:
3195 * http://developer.yahoo.net/yui/license.txt
3196 * <script type="text/javascript">
3199 //@@dep Roo.lib.Region
3202 Roo.lib.Point = function(x, y) {
3203 if (x instanceof Array) {
3207 this.x = this.right = this.left = this[0] = x;
3208 this.y = this.top = this.bottom = this[1] = y;
3211 Roo.lib.Point.prototype = new Roo.lib.Region();
3213 * Portions of this file are based on pieces of Yahoo User Interface Library
3214 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3215 * YUI licensed under the BSD License:
3216 * http://developer.yahoo.net/yui/license.txt
3217 * <script type="text/javascript">
3224 scroll : function(el, args, duration, easing, cb, scope) {
3225 this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3228 motion : function(el, args, duration, easing, cb, scope) {
3229 this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3232 color : function(el, args, duration, easing, cb, scope) {
3233 this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3236 run : function(el, args, duration, easing, cb, scope, type) {
3237 type = type || Roo.lib.AnimBase;
3238 if (typeof easing == "string") {
3239 easing = Roo.lib.Easing[easing];
3241 var anim = new type(el, args, duration, easing);
3242 anim.animateX(function() {
3243 Roo.callback(cb, scope);
3249 * Portions of this file are based on pieces of Yahoo User Interface Library
3250 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3251 * YUI licensed under the BSD License:
3252 * http://developer.yahoo.net/yui/license.txt
3253 * <script type="text/javascript">
3261 if (!libFlyweight) {
3262 libFlyweight = new Roo.Element.Flyweight();
3264 libFlyweight.dom = el;
3265 return libFlyweight;
3268 // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3272 Roo.lib.AnimBase = function(el, attributes, duration, method) {
3274 this.init(el, attributes, duration, method);
3278 Roo.lib.AnimBase.fly = fly;
3282 Roo.lib.AnimBase.prototype = {
3284 toString: function() {
3285 var el = this.getEl();
3286 var id = el.id || el.tagName;
3287 return ("Anim " + id);
3291 noNegatives: /width|height|opacity|padding/i,
3292 offsetAttribute: /^((width|height)|(top|left))$/,
3293 defaultUnit: /width|height|top$|bottom$|left$|right$/i,
3294 offsetUnit: /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3298 doMethod: function(attr, start, end) {
3299 return this.method(this.currentFrame, start, end - start, this.totalFrames);
3303 setAttribute: function(attr, val, unit) {
3304 if (this.patterns.noNegatives.test(attr)) {
3305 val = (val > 0) ? val : 0;
3308 Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3312 getAttribute: function(attr) {
3313 var el = this.getEl();
3314 var val = fly(el).getStyle(attr);
3316 if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3317 return parseFloat(val);
3320 var a = this.patterns.offsetAttribute.exec(attr) || [];
3321 var pos = !!( a[3] );
3322 var box = !!( a[2] );
3325 if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3326 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3335 getDefaultUnit: function(attr) {
3336 if (this.patterns.defaultUnit.test(attr)) {
3343 animateX : function(callback, scope) {
3344 var f = function() {
3345 this.onComplete.removeListener(f);
3346 if (typeof callback == "function") {
3347 callback.call(scope || this, this);
3350 this.onComplete.addListener(f, this);
3355 setRuntimeAttribute: function(attr) {
3358 var attributes = this.attributes;
3360 this.runtimeAttributes[attr] = {};
3362 var isset = function(prop) {
3363 return (typeof prop !== 'undefined');
3366 if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3370 start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3373 if (isset(attributes[attr]['to'])) {
3374 end = attributes[attr]['to'];
3375 } else if (isset(attributes[attr]['by'])) {
3376 if (start.constructor == Array) {
3378 for (var i = 0, len = start.length; i < len; ++i) {
3379 end[i] = start[i] + attributes[attr]['by'][i];
3382 end = start + attributes[attr]['by'];
3386 this.runtimeAttributes[attr].start = start;
3387 this.runtimeAttributes[attr].end = end;
3390 this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3394 init: function(el, attributes, duration, method) {
3396 var isAnimated = false;
3399 var startTime = null;
3402 var actualFrames = 0;
3405 el = Roo.getDom(el);
3408 this.attributes = attributes || {};
3411 this.duration = duration || 1;
3414 this.method = method || Roo.lib.Easing.easeNone;
3417 this.useSeconds = true;
3420 this.currentFrame = 0;
3423 this.totalFrames = Roo.lib.AnimMgr.fps;
3426 this.getEl = function() {
3431 this.isAnimated = function() {
3436 this.getStartTime = function() {
3440 this.runtimeAttributes = {};
3443 this.animate = function() {
3444 if (this.isAnimated()) {
3448 this.currentFrame = 0;
3450 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3452 Roo.lib.AnimMgr.registerElement(this);
3456 this.stop = function(finish) {
3458 this.currentFrame = this.totalFrames;
3459 this._onTween.fire();
3461 Roo.lib.AnimMgr.stop(this);
3464 var onStart = function() {
3465 this.onStart.fire();
3467 this.runtimeAttributes = {};
3468 for (var attr in this.attributes) {
3469 this.setRuntimeAttribute(attr);
3474 startTime = new Date();
3478 var onTween = function() {
3480 duration: new Date() - this.getStartTime(),
3481 currentFrame: this.currentFrame
3484 data.toString = function() {
3486 'duration: ' + data.duration +
3487 ', currentFrame: ' + data.currentFrame
3491 this.onTween.fire(data);
3493 var runtimeAttributes = this.runtimeAttributes;
3495 for (var attr in runtimeAttributes) {
3496 this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3502 var onComplete = function() {
3503 var actual_duration = (new Date() - startTime) / 1000 ;
3506 duration: actual_duration,
3507 frames: actualFrames,
3508 fps: actualFrames / actual_duration
3511 data.toString = function() {
3513 'duration: ' + data.duration +
3514 ', frames: ' + data.frames +
3515 ', fps: ' + data.fps
3521 this.onComplete.fire(data);
3525 this._onStart = new Roo.util.Event(this);
3526 this.onStart = new Roo.util.Event(this);
3527 this.onTween = new Roo.util.Event(this);
3528 this._onTween = new Roo.util.Event(this);
3529 this.onComplete = new Roo.util.Event(this);
3530 this._onComplete = new Roo.util.Event(this);
3531 this._onStart.addListener(onStart);
3532 this._onTween.addListener(onTween);
3533 this._onComplete.addListener(onComplete);
3538 * Portions of this file are based on pieces of Yahoo User Interface Library
3539 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3540 * YUI licensed under the BSD License:
3541 * http://developer.yahoo.net/yui/license.txt
3542 * <script type="text/javascript">
3546 Roo.lib.AnimMgr = new function() {
3563 this.registerElement = function(tween) {
3564 queue[queue.length] = tween;
3566 tween._onStart.fire();
3571 this.unRegister = function(tween, index) {
3572 tween._onComplete.fire();
3573 index = index || getIndex(tween);
3575 queue.splice(index, 1);
3579 if (tweenCount <= 0) {
3585 this.start = function() {
3586 if (thread === null) {
3587 thread = setInterval(this.run, this.delay);
3592 this.stop = function(tween) {
3594 clearInterval(thread);
3596 for (var i = 0, len = queue.length; i < len; ++i) {
3597 if (queue[0].isAnimated()) {
3598 this.unRegister(queue[0], 0);
3607 this.unRegister(tween);
3612 this.run = function() {
3613 for (var i = 0, len = queue.length; i < len; ++i) {
3614 var tween = queue[i];
3615 if (!tween || !tween.isAnimated()) {
3619 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3621 tween.currentFrame += 1;
3623 if (tween.useSeconds) {
3624 correctFrame(tween);
3626 tween._onTween.fire();
3629 Roo.lib.AnimMgr.stop(tween, i);
3634 var getIndex = function(anim) {
3635 for (var i = 0, len = queue.length; i < len; ++i) {
3636 if (queue[i] == anim) {
3644 var correctFrame = function(tween) {
3645 var frames = tween.totalFrames;
3646 var frame = tween.currentFrame;
3647 var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3648 var elapsed = (new Date() - tween.getStartTime());
3651 if (elapsed < tween.duration * 1000) {
3652 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3654 tweak = frames - (frame + 1);
3656 if (tweak > 0 && isFinite(tweak)) {
3657 if (tween.currentFrame + tweak >= frames) {
3658 tweak = frames - (frame + 1);
3661 tween.currentFrame += tweak;
3667 * Portions of this file are based on pieces of Yahoo User Interface Library
3668 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3669 * YUI licensed under the BSD License:
3670 * http://developer.yahoo.net/yui/license.txt
3671 * <script type="text/javascript">
3674 Roo.lib.Bezier = new function() {
3676 this.getPosition = function(points, t) {
3677 var n = points.length;
3680 for (var i = 0; i < n; ++i) {
3681 tmp[i] = [points[i][0], points[i][1]];
3684 for (var j = 1; j < n; ++j) {
3685 for (i = 0; i < n - j; ++i) {
3686 tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3687 tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3691 return [ tmp[0][0], tmp[0][1] ];
3697 * @class Roo.lib.Color
3699 * An abstract Color implementation. Concrete Color implementations should use
3700 * an instance of this function as their prototype, and implement the getRGB and
3701 * getHSL functions. getRGB should return an object representing the RGB
3702 * components of this Color, with the red, green, and blue components in the
3703 * range [0,255] and the alpha component in the range [0,100]. getHSL should
3704 * return an object representing the HSL components of this Color, with the hue
3705 * component in the range [0,360), the saturation and lightness components in
3706 * the range [0,100], and the alpha component in the range [0,1].
3711 * Functions for Color handling and processing.
3713 * http://www.safalra.com/web-design/javascript/Color-handling-and-processing/
3715 * The author of this program, Safalra (Stephen Morley), irrevocably releases all
3716 * rights to this program, with the intention of it becoming part of the public
3717 * domain. Because this program is released into the public domain, it comes with
3718 * no warranty either expressed or implied, to the extent permitted by law.
3720 * For more free and public domain JavaScript code by the same author, visit:
3721 * http://www.safalra.com/web-design/javascript/
3724 Roo.lib.Color = function() { }
3727 Roo.apply(Roo.lib.Color.prototype, {
3735 * @return {Object} an object representing the RGBA components of this Color. The red,
3736 * green, and blue components are converted to integers in the range [0,255].
3737 * The alpha is a value in the range [0,1].
3739 getIntegerRGB : function(){
3741 // get the RGB components of this Color
3742 var rgb = this.getRGB();
3744 // return the integer components
3746 'r' : Math.round(rgb.r),
3747 'g' : Math.round(rgb.g),
3748 'b' : Math.round(rgb.b),
3756 * @return {Object} an object representing the RGBA components of this Color. The red,
3757 * green, and blue components are converted to numbers in the range [0,100].
3758 * The alpha is a value in the range [0,1].
3760 getPercentageRGB : function(){
3762 // get the RGB components of this Color
3763 var rgb = this.getRGB();
3765 // return the percentage components
3767 'r' : 100 * rgb.r / 255,
3768 'g' : 100 * rgb.g / 255,
3769 'b' : 100 * rgb.b / 255,
3776 * getCSSHexadecimalRGB
3777 * @return {String} a string representing this Color as a CSS hexadecimal RGB Color
3778 * value - that is, a string of the form #RRGGBB where each of RR, GG, and BB
3779 * are two-digit hexadecimal numbers.
3781 getCSSHexadecimalRGB : function()
3784 // get the integer RGB components
3785 var rgb = this.getIntegerRGB();
3787 // determine the hexadecimal equivalents
3788 var r16 = rgb.r.toString(16);
3789 var g16 = rgb.g.toString(16);
3790 var b16 = rgb.b.toString(16);
3792 // return the CSS RGB Color value
3794 + (r16.length == 2 ? r16 : '0' + r16)
3795 + (g16.length == 2 ? g16 : '0' + g16)
3796 + (b16.length == 2 ? b16 : '0' + b16);
3802 * @return {String} a string representing this Color as a CSS integer RGB Color
3803 * value - that is, a string of the form rgb(r,g,b) where each of r, g, and b
3804 * are integers in the range [0,255].
3806 getCSSIntegerRGB : function(){
3808 // get the integer RGB components
3809 var rgb = this.getIntegerRGB();
3811 // return the CSS RGB Color value
3812 return 'rgb(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ')';
3818 * @return {String} Returns a string representing this Color as a CSS integer RGBA Color
3819 * value - that is, a string of the form rgba(r,g,b,a) where each of r, g, and
3820 * b are integers in the range [0,255] and a is in the range [0,1].
3822 getCSSIntegerRGBA : function(){
3824 // get the integer RGB components
3825 var rgb = this.getIntegerRGB();
3827 // return the CSS integer RGBA Color value
3828 return 'rgb(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ',' + rgb.a + ')';
3833 * getCSSPercentageRGB
3834 * @return {String} a string representing this Color as a CSS percentage RGB Color
3835 * value - that is, a string of the form rgb(r%,g%,b%) where each of r, g, and
3836 * b are in the range [0,100].
3838 getCSSPercentageRGB : function(){
3840 // get the percentage RGB components
3841 var rgb = this.getPercentageRGB();
3843 // return the CSS RGB Color value
3844 return 'rgb(' + rgb.r + '%,' + rgb.g + '%,' + rgb.b + '%)';
3849 * getCSSPercentageRGBA
3850 * @return {String} a string representing this Color as a CSS percentage RGBA Color
3851 * value - that is, a string of the form rgba(r%,g%,b%,a) where each of r, g,
3852 * and b are in the range [0,100] and a is in the range [0,1].
3854 getCSSPercentageRGBA : function(){
3856 // get the percentage RGB components
3857 var rgb = this.getPercentageRGB();
3859 // return the CSS percentage RGBA Color value
3860 return 'rgb(' + rgb.r + '%,' + rgb.g + '%,' + rgb.b + '%,' + rgb.a + ')';
3866 * @return {String} a string representing this Color as a CSS HSL Color value - that
3867 * is, a string of the form hsl(h,s%,l%) where h is in the range [0,100] and
3868 * s and l are in the range [0,100].
3870 getCSSHSL : function(){
3872 // get the HSL components
3873 var hsl = this.getHSL();
3875 // return the CSS HSL Color value
3876 return 'hsl(' + hsl.h + ',' + hsl.s + '%,' + hsl.l + '%)';
3882 * @return {String} a string representing this Color as a CSS HSLA Color value - that
3883 * is, a string of the form hsla(h,s%,l%,a) where h is in the range [0,100],
3884 * s and l are in the range [0,100], and a is in the range [0,1].
3886 getCSSHSLA : function(){
3888 // get the HSL components
3889 var hsl = this.getHSL();
3891 // return the CSS HSL Color value
3892 return 'hsl(' + hsl.h + ',' + hsl.s + '%,' + hsl.l + '%,' + hsl.a + ')';
3897 * Sets the Color of the specified node to this Color. This functions sets
3898 * the CSS 'color' property for the node. The parameter is:
3900 * @param {DomElement} node - the node whose Color should be set
3902 setNodeColor : function(node){
3904 // set the Color of the node
3905 node.style.color = this.getCSSHexadecimalRGB();
3910 * Sets the background Color of the specified node to this Color. This
3911 * functions sets the CSS 'background-color' property for the node. The
3914 * @param {DomElement} node - the node whose background Color should be set
3916 setNodeBackgroundColor : function(node){
3918 // set the background Color of the node
3919 node.style.backgroundColor = this.getCSSHexadecimalRGB();
3922 // convert between formats..
3925 var r = this.getIntegerRGB();
3926 return new Roo.lib.RGBColor(r.r,r.g,r.b,r.a);
3931 var hsl = this.getHSL();
3932 // return the CSS HSL Color value
3933 return new Roo.lib.HSLColor(hsl.h, hsl.s, hsl.l , hsl.a );
3939 var rgb = this.toRGB();
3940 var hsv = rgb.getHSV();
3941 // return the CSS HSL Color value
3942 return new Roo.lib.HSVColor(hsv.h, hsv.s, hsv.v , hsv.a );
3946 // modify v = 0 ... 1 (eg. 0.5)
3947 saturate : function(v)
3949 var rgb = this.toRGB();
3950 var hsv = rgb.getHSV();
3951 return new Roo.lib.HSVColor(hsv.h, hsv.s * v, hsv.v , hsv.a );
3959 * @return {Object} the RGB and alpha components of this Color as an object with r,
3960 * g, b, and a properties. r, g, and b are in the range [0,255] and a is in
3965 // return the RGB components
3977 * @return {Object} the HSV and alpha components of this Color as an object with h,
3978 * s, v, and a properties. h is in the range [0,360), s and v are in the range
3979 * [0,100], and a is in the range [0,1].
3984 // calculate the HSV components if necessary
3985 if (this.hsv == null) {
3986 this.calculateHSV();
3989 // return the HSV components
4001 * @return {Object} the HSL and alpha components of this Color as an object with h,
4002 * s, l, and a properties. h is in the range [0,360), s and l are in the range
4003 * [0,100], and a is in the range [0,1].
4005 getHSL : function(){
4008 // calculate the HSV components if necessary
4009 if (this.hsl == null) { this.calculateHSL(); }
4011 // return the HSL components
4026 * @class Roo.lib.RGBColor
4027 * @extends Roo.lib.Color
4028 * Creates a Color specified in the RGB Color space, with an optional alpha
4029 * component. The parameters are:
4033 * @param {Number} r - the red component, clipped to the range [0,255]
4034 * @param {Number} g - the green component, clipped to the range [0,255]
4035 * @param {Number} b - the blue component, clipped to the range [0,255]
4036 * @param {Number} a - the alpha component, clipped to the range [0,1] - this parameter is
4037 * optional and defaults to 1
4039 Roo.lib.RGBColor = function (r, g, b, a){
4041 // store the alpha component after clipping it if necessary
4042 this.alpha = (a === undefined ? 1 : Math.max(0, Math.min(1, a)));
4044 // store the RGB components after clipping them if necessary
4047 'r' : Math.max(0, Math.min(255, r)),
4048 'g' : Math.max(0, Math.min(255, g)),
4049 'b' : Math.max(0, Math.min(255, b))
4052 // initialise the HSV and HSL components to null
4056 * //private returns the HSV or HSL hue component of this RGBColor. The hue is in the
4057 * range [0,360). The parameters are:
4059 * maximum - the maximum of the RGB component values
4060 * range - the range of the RGB component values
4065 // this does an 'exteds'
4066 Roo.extend(Roo.lib.RGBColor, Roo.lib.Color, {
4069 getHue : function(maximum, range)
4073 // check whether the range is zero
4076 // set the hue to zero (any hue is acceptable as the Color is grey)
4081 // determine which of the components has the highest value and set the hue
4084 // red has the highest value
4086 var hue = (rgb.g - rgb.b) / range * 60;
4087 if (hue < 0) { hue += 360; }
4090 // green has the highest value
4092 var hue = (rgb.b - rgb.r) / range * 60 + 120;
4095 // blue has the highest value
4097 var hue = (rgb.r - rgb.g) / range * 60 + 240;
4109 /* //private Calculates and stores the HSV components of this RGBColor so that they can
4110 * be returned be the getHSV function.
4112 calculateHSV : function(){
4114 // get the maximum and range of the RGB component values
4115 var maximum = Math.max(rgb.r, rgb.g, rgb.b);
4116 var range = maximum - Math.min(rgb.r, rgb.g, rgb.b);
4118 // store the HSV components
4121 'h' : this.getHue(maximum, range),
4122 's' : (maximum == 0 ? 0 : 100 * range / maximum),
4123 'v' : maximum / 2.55
4128 /* //private Calculates and stores the HSL components of this RGBColor so that they can
4129 * be returned be the getHSL function.
4131 calculateHSL : function(){
4133 // get the maximum and range of the RGB component values
4134 var maximum = Math.max(rgb.r, rgb.g, rgb.b);
4135 var range = maximum - Math.min(rgb.r, rgb.g, rgb.b);
4137 // determine the lightness in the range [0,1]
4138 var l = maximum / 255 - range / 510;
4140 // store the HSL components
4143 'h' : this.getHue(maximum, range),
4144 's' : (range == 0 ? 0 : range / 2.55 / (l < 0.5 ? l * 2 : 2 - l * 2)),
4153 * @class Roo.lib.HSVColor
4154 * @extends Roo.lib.Color
4155 * Creates a Color specified in the HSV Color space, with an optional alpha
4156 * component. The parameters are:
4159 * @param {Number} h - the hue component, wrapped to the range [0,360)
4160 * @param {Number} s - the saturation component, clipped to the range [0,100]
4161 * @param {Number} v - the value component, clipped to the range [0,100]
4162 * @param {Number} a - the alpha component, clipped to the range [0,1] - this parameter is
4163 * optional and defaults to 1
4165 Roo.lib.HSVColor = function (h, s, v, a){
4167 // store the alpha component after clipping it if necessary
4168 this.alpha = (a === undefined ? 1 : Math.max(0, Math.min(1, a)));
4170 // store the HSV components after clipping or wrapping them if necessary
4173 'h' : (h % 360 + 360) % 360,
4174 's' : Math.max(0, Math.min(100, s)),
4175 'v' : Math.max(0, Math.min(100, v))
4178 // initialise the RGB and HSL components to null
4183 Roo.extend(Roo.lib.HSVColor, Roo.lib.Color, {
4184 /* Calculates and stores the RGB components of this HSVColor so that they can
4185 * be returned be the getRGB function.
4187 calculateRGB: function ()
4190 // check whether the saturation is zero
4193 // set the Color to the appropriate shade of grey
4200 // set some temporary values
4201 var f = hsv.h / 60 - Math.floor(hsv.h / 60);
4202 var p = hsv.v * (1 - hsv.s / 100);
4203 var q = hsv.v * (1 - hsv.s / 100 * f);
4204 var t = hsv.v * (1 - hsv.s / 100 * (1 - f));
4206 // set the RGB Color components to their temporary values
4207 switch (Math.floor(hsv.h / 60)){
4208 case 0: var r = hsv.v; var g = t; var b = p; break;
4209 case 1: var r = q; var g = hsv.v; var b = p; break;
4210 case 2: var r = p; var g = hsv.v; var b = t; break;
4211 case 3: var r = p; var g = q; var b = hsv.v; break;
4212 case 4: var r = t; var g = p; var b = hsv.v; break;
4213 case 5: var r = hsv.v; var g = p; var b = q; break;
4218 // store the RGB components
4228 /* Calculates and stores the HSL components of this HSVColor so that they can
4229 * be returned be the getHSL function.
4231 calculateHSL : function (){
4234 // determine the lightness in the range [0,100]
4235 var l = (2 - hsv.s / 100) * hsv.v / 2;
4237 // store the HSL components
4241 's' : hsv.s * hsv.v / (l < 50 ? l * 2 : 200 - l * 2),
4245 // correct a division-by-zero error
4246 if (isNaN(hsl.s)) { hsl.s = 0; }
4255 * @class Roo.lib.HSLColor
4256 * @extends Roo.lib.Color
4259 * Creates a Color specified in the HSL Color space, with an optional alpha
4260 * component. The parameters are:
4262 * @param {Number} h - the hue component, wrapped to the range [0,360)
4263 * @param {Number} s - the saturation component, clipped to the range [0,100]
4264 * @param {Number} l - the lightness component, clipped to the range [0,100]
4265 * @param {Number} a - the alpha component, clipped to the range [0,1] - this parameter is
4266 * optional and defaults to 1
4269 Roo.lib.HSLColor = function(h, s, l, a){
4271 // store the alpha component after clipping it if necessary
4272 this.alpha = (a === undefined ? 1 : Math.max(0, Math.min(1, a)));
4274 // store the HSL components after clipping or wrapping them if necessary
4277 'h' : (h % 360 + 360) % 360,
4278 's' : Math.max(0, Math.min(100, s)),
4279 'l' : Math.max(0, Math.min(100, l))
4282 // initialise the RGB and HSV components to null
4285 Roo.extend(Roo.lib.HSLColor, Roo.lib.Color, {
4287 /* Calculates and stores the RGB components of this HSLColor so that they can
4288 * be returned be the getRGB function.
4290 calculateRGB: function (){
4292 // check whether the saturation is zero
4293 if (this.hsl.s == 0){
4295 // store the RGB components representing the appropriate shade of grey
4298 'r' : this.hsl.l * 2.55,
4299 'g' : this.hsl.l * 2.55,
4300 'b' : this.hsl.l * 2.55
4305 // set some temporary values
4306 var p = this.hsl.l < 50
4307 ? this.hsl.l * (1 + hsl.s / 100)
4308 : this.hsl.l + hsl.s - hsl.l * hsl.s / 100;
4309 var q = 2 * hsl.l - p;
4311 // initialise the RGB components
4314 'r' : (h + 120) / 60 % 6,
4316 'b' : (h + 240) / 60 % 6
4319 // loop over the RGB components
4320 for (var key in this.rgb){
4322 // ensure that the property is not inherited from the root object
4323 if (this.rgb.hasOwnProperty(key)){
4325 // set the component to its value in the range [0,100]
4326 if (this.rgb[key] < 1){
4327 this.rgb[key] = q + (p - q) * this.rgb[key];
4328 }else if (this.rgb[key] < 3){
4330 }else if (this.rgb[key] < 4){
4331 this.rgb[key] = q + (p - q) * (4 - this.rgb[key]);
4336 // set the component to its value in the range [0,255]
4337 this.rgb[key] *= 2.55;
4347 /* Calculates and stores the HSV components of this HSLColor so that they can
4348 * be returned be the getHSL function.
4350 calculateHSV : function(){
4352 // set a temporary value
4353 var t = this.hsl.s * (this.hsl.l < 50 ? this.hsl.l : 100 - this.hsl.l) / 100;
4355 // store the HSV components
4359 's' : 200 * t / (this.hsl.l + t),
4360 'v' : t + this.hsl.l
4363 // correct a division-by-zero error
4364 if (isNaN(this.hsv.s)) { this.hsv.s = 0; }
4371 * Portions of this file are based on pieces of Yahoo User Interface Library
4372 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4373 * YUI licensed under the BSD License:
4374 * http://developer.yahoo.net/yui/license.txt
4375 * <script type="text/javascript">
4380 Roo.lib.ColorAnim = function(el, attributes, duration, method) {
4381 Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
4384 Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
4386 var fly = Roo.lib.AnimBase.fly;
4388 var superclass = Y.ColorAnim.superclass;
4389 var proto = Y.ColorAnim.prototype;
4391 proto.toString = function() {
4392 var el = this.getEl();
4393 var id = el.id || el.tagName;
4394 return ("ColorAnim " + id);
4397 proto.patterns.color = /color$/i;
4398 proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
4399 proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
4400 proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
4401 proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
4404 proto.parseColor = function(s) {
4405 if (s.length == 3) {
4409 var c = this.patterns.hex.exec(s);
4410 if (c && c.length == 4) {
4411 return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
4414 c = this.patterns.rgb.exec(s);
4415 if (c && c.length == 4) {
4416 return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
4419 c = this.patterns.hex3.exec(s);
4420 if (c && c.length == 4) {
4421 return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
4426 // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
4427 proto.getAttribute = function(attr) {
4428 var el = this.getEl();
4429 if (this.patterns.color.test(attr)) {
4430 var val = fly(el).getStyle(attr);
4432 if (this.patterns.transparent.test(val)) {
4433 var parent = el.parentNode;
4434 val = fly(parent).getStyle(attr);
4436 while (parent && this.patterns.transparent.test(val)) {
4437 parent = parent.parentNode;
4438 val = fly(parent).getStyle(attr);
4439 if (parent.tagName.toUpperCase() == 'HTML') {
4445 val = superclass.getAttribute.call(this, attr);
4450 proto.getAttribute = function(attr) {
4451 var el = this.getEl();
4452 if (this.patterns.color.test(attr)) {
4453 var val = fly(el).getStyle(attr);
4455 if (this.patterns.transparent.test(val)) {
4456 var parent = el.parentNode;
4457 val = fly(parent).getStyle(attr);
4459 while (parent && this.patterns.transparent.test(val)) {
4460 parent = parent.parentNode;
4461 val = fly(parent).getStyle(attr);
4462 if (parent.tagName.toUpperCase() == 'HTML') {
4468 val = superclass.getAttribute.call(this, attr);
4474 proto.doMethod = function(attr, start, end) {
4477 if (this.patterns.color.test(attr)) {
4479 for (var i = 0, len = start.length; i < len; ++i) {
4480 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
4483 val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
4486 val = superclass.doMethod.call(this, attr, start, end);
4492 proto.setRuntimeAttribute = function(attr) {
4493 superclass.setRuntimeAttribute.call(this, attr);
4495 if (this.patterns.color.test(attr)) {
4496 var attributes = this.attributes;
4497 var start = this.parseColor(this.runtimeAttributes[attr].start);
4498 var end = this.parseColor(this.runtimeAttributes[attr].end);
4500 if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
4501 end = this.parseColor(attributes[attr].by);
4503 for (var i = 0, len = start.length; i < len; ++i) {
4504 end[i] = start[i] + end[i];
4508 this.runtimeAttributes[attr].start = start;
4509 this.runtimeAttributes[attr].end = end;
4515 * Portions of this file are based on pieces of Yahoo User Interface Library
4516 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4517 * YUI licensed under the BSD License:
4518 * http://developer.yahoo.net/yui/license.txt
4519 * <script type="text/javascript">
4525 easeNone: function (t, b, c, d) {
4526 return c * t / d + b;
4530 easeIn: function (t, b, c, d) {
4531 return c * (t /= d) * t + b;
4535 easeOut: function (t, b, c, d) {
4536 return -c * (t /= d) * (t - 2) + b;
4540 easeBoth: function (t, b, c, d) {
4541 if ((t /= d / 2) < 1) {
4542 return c / 2 * t * t + b;
4545 return -c / 2 * ((--t) * (t - 2) - 1) + b;
4549 easeInStrong: function (t, b, c, d) {
4550 return c * (t /= d) * t * t * t + b;
4554 easeOutStrong: function (t, b, c, d) {
4555 return -c * ((t = t / d - 1) * t * t * t - 1) + b;
4559 easeBothStrong: function (t, b, c, d) {
4560 if ((t /= d / 2) < 1) {
4561 return c / 2 * t * t * t * t + b;
4564 return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
4569 elasticIn: function (t, b, c, d, a, p) {
4573 if ((t /= d) == 1) {
4580 if (!a || a < Math.abs(c)) {
4585 var s = p / (2 * Math.PI) * Math.asin(c / a);
4588 return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
4592 elasticOut: function (t, b, c, d, a, p) {
4596 if ((t /= d) == 1) {
4603 if (!a || a < Math.abs(c)) {
4608 var s = p / (2 * Math.PI) * Math.asin(c / a);
4611 return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
4615 elasticBoth: function (t, b, c, d, a, p) {
4620 if ((t /= d / 2) == 2) {
4628 if (!a || a < Math.abs(c)) {
4633 var s = p / (2 * Math.PI) * Math.asin(c / a);
4637 return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
4638 Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
4640 return a * Math.pow(2, -10 * (t -= 1)) *
4641 Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
4646 backIn: function (t, b, c, d, s) {
4647 if (typeof s == 'undefined') {
4650 return c * (t /= d) * t * ((s + 1) * t - s) + b;
4654 backOut: function (t, b, c, d, s) {
4655 if (typeof s == 'undefined') {
4658 return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
4662 backBoth: function (t, b, c, d, s) {
4663 if (typeof s == 'undefined') {
4667 if ((t /= d / 2 ) < 1) {
4668 return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
4670 return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
4674 bounceIn: function (t, b, c, d) {
4675 return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
4679 bounceOut: function (t, b, c, d) {
4680 if ((t /= d) < (1 / 2.75)) {
4681 return c * (7.5625 * t * t) + b;
4682 } else if (t < (2 / 2.75)) {
4683 return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
4684 } else if (t < (2.5 / 2.75)) {
4685 return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
4687 return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
4691 bounceBoth: function (t, b, c, d) {
4693 return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
4695 return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
4698 * Portions of this file are based on pieces of Yahoo User Interface Library
4699 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4700 * YUI licensed under the BSD License:
4701 * http://developer.yahoo.net/yui/license.txt
4702 * <script type="text/javascript">
4706 Roo.lib.Motion = function(el, attributes, duration, method) {
4708 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
4712 Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
4716 var superclass = Y.Motion.superclass;
4717 var proto = Y.Motion.prototype;
4719 proto.toString = function() {
4720 var el = this.getEl();
4721 var id = el.id || el.tagName;
4722 return ("Motion " + id);
4725 proto.patterns.points = /^points$/i;
4727 proto.setAttribute = function(attr, val, unit) {
4728 if (this.patterns.points.test(attr)) {
4729 unit = unit || 'px';
4730 superclass.setAttribute.call(this, 'left', val[0], unit);
4731 superclass.setAttribute.call(this, 'top', val[1], unit);
4733 superclass.setAttribute.call(this, attr, val, unit);
4737 proto.getAttribute = function(attr) {
4738 if (this.patterns.points.test(attr)) {
4740 superclass.getAttribute.call(this, 'left'),
4741 superclass.getAttribute.call(this, 'top')
4744 val = superclass.getAttribute.call(this, attr);
4750 proto.doMethod = function(attr, start, end) {
4753 if (this.patterns.points.test(attr)) {
4754 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
4755 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
4757 val = superclass.doMethod.call(this, attr, start, end);
4762 proto.setRuntimeAttribute = function(attr) {
4763 if (this.patterns.points.test(attr)) {
4764 var el = this.getEl();
4765 var attributes = this.attributes;
4767 var control = attributes['points']['control'] || [];
4771 if (control.length > 0 && !(control[0] instanceof Array)) {
4772 control = [control];
4775 for (i = 0,len = control.length; i < len; ++i) {
4776 tmp[i] = control[i];
4781 Roo.fly(el).position();
4783 if (isset(attributes['points']['from'])) {
4784 Roo.lib.Dom.setXY(el, attributes['points']['from']);
4787 Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
4790 start = this.getAttribute('points');
4793 if (isset(attributes['points']['to'])) {
4794 end = translateValues.call(this, attributes['points']['to'], start);
4796 var pageXY = Roo.lib.Dom.getXY(this.getEl());
4797 for (i = 0,len = control.length; i < len; ++i) {
4798 control[i] = translateValues.call(this, control[i], start);
4802 } else if (isset(attributes['points']['by'])) {
4803 end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
4805 for (i = 0,len = control.length; i < len; ++i) {
4806 control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
4810 this.runtimeAttributes[attr] = [start];
4812 if (control.length > 0) {
4813 this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
4816 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
4819 superclass.setRuntimeAttribute.call(this, attr);
4823 var translateValues = function(val, start) {
4824 var pageXY = Roo.lib.Dom.getXY(this.getEl());
4825 val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4830 var isset = function(prop) {
4831 return (typeof prop !== 'undefined');
4835 * Portions of this file are based on pieces of Yahoo User Interface Library
4836 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4837 * YUI licensed under the BSD License:
4838 * http://developer.yahoo.net/yui/license.txt
4839 * <script type="text/javascript">
4843 Roo.lib.Scroll = function(el, attributes, duration, method) {
4845 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4849 Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4853 var superclass = Y.Scroll.superclass;
4854 var proto = Y.Scroll.prototype;
4856 proto.toString = function() {
4857 var el = this.getEl();
4858 var id = el.id || el.tagName;
4859 return ("Scroll " + id);
4862 proto.doMethod = function(attr, start, end) {
4865 if (attr == 'scroll') {
4867 this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4868 this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4872 val = superclass.doMethod.call(this, attr, start, end);
4877 proto.getAttribute = function(attr) {
4879 var el = this.getEl();
4881 if (attr == 'scroll') {
4882 val = [ el.scrollLeft, el.scrollTop ];
4884 val = superclass.getAttribute.call(this, attr);
4890 proto.setAttribute = function(attr, val, unit) {
4891 var el = this.getEl();
4893 if (attr == 'scroll') {
4894 el.scrollLeft = val[0];
4895 el.scrollTop = val[1];
4897 superclass.setAttribute.call(this, attr, val, unit);
4903 * Ext JS Library 1.1.1
4904 * Copyright(c) 2006-2007, Ext JS, LLC.
4906 * Originally Released Under LGPL - original licence link has changed is not relivant.
4909 * <script type="text/javascript">
4913 // nasty IE9 hack - what a pile of crap that is..
4915 if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4916 Range.prototype.createContextualFragment = function (html) {
4917 var doc = window.document;
4918 var container = doc.createElement("div");
4919 container.innerHTML = html;
4920 var frag = doc.createDocumentFragment(), n;
4921 while ((n = container.firstChild)) {
4922 frag.appendChild(n);
4929 * @class Roo.DomHelper
4930 * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4931 * For more information see <a href="http://web.archive.org/web/20071221063734/http://www.jackslocum.com/blog/2006/10/06/domhelper-create-elements-using-dom-html-fragments-or-templates/">this blog post with examples</a>.
4934 Roo.DomHelper = function(){
4935 var tempTableEl = null;
4936 var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4937 var tableRe = /^table|tbody|tr|td$/i;
4939 // build as innerHTML where available
4941 var createHtml = function(o){
4942 if(typeof o == 'string'){
4951 if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") { continue; }
4952 if(attr == "style"){
4954 if(typeof s == "function"){
4957 if(typeof s == "string"){
4958 b += ' style="' + s + '"';
4959 }else if(typeof s == "object"){
4962 if(typeof s[key] != "function"){
4963 b += key + ":" + s[key] + ";";
4970 b += ' class="' + o["cls"] + '"';
4971 }else if(attr == "htmlFor"){
4972 b += ' for="' + o["htmlFor"] + '"';
4974 b += " " + attr + '="' + o[attr] + '"';
4978 if(emptyTags.test(o.tag)){
4982 var cn = o.children || o.cn;
4984 //http://bugs.kde.org/show_bug.cgi?id=71506
4985 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4986 for(var i = 0, len = cn.length; i < len; i++) {
4987 b += createHtml(cn[i], b);
4990 b += createHtml(cn, b);
4996 b += "</" + o.tag + ">";
5003 var createDom = function(o, parentNode){
5005 // defininition craeted..
5007 if (o.ns && o.ns != 'html') {
5009 if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
5010 xmlns[o.ns] = o.xmlns;
5013 if (typeof(xmlns[o.ns]) == 'undefined') {
5014 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
5020 if (typeof(o) == 'string') {
5021 return parentNode.appendChild(document.createTextNode(o));
5023 o.tag = o.tag || div;
5024 if (o.ns && Roo.isIE) {
5026 o.tag = o.ns + ':' + o.tag;
5029 var el = ns ? document.createElementNS( ns, o.tag||'div') : document.createElement(o.tag||'div');
5030 var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
5033 if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" ||
5034 attr == "style" || typeof o[attr] == "function") { continue; }
5036 if(attr=="cls" && Roo.isIE){
5037 el.className = o["cls"];
5039 if(useSet) { el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);}
5045 Roo.DomHelper.applyStyles(el, o.style);
5046 var cn = o.children || o.cn;
5048 //http://bugs.kde.org/show_bug.cgi?id=71506
5049 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
5050 for(var i = 0, len = cn.length; i < len; i++) {
5051 createDom(cn[i], el);
5058 el.innerHTML = o.html;
5061 parentNode.appendChild(el);
5066 var ieTable = function(depth, s, h, e){
5067 tempTableEl.innerHTML = [s, h, e].join('');
5068 var i = -1, el = tempTableEl;
5069 while(++i < depth && el.firstChild){
5075 // kill repeat to save bytes
5079 tbe = '</tbody>'+te,
5085 * Nasty code for IE's broken table implementation
5087 var insertIntoTable = function(tag, where, el, html){
5089 tempTableEl = document.createElement('div');
5094 if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
5097 if(where == 'beforebegin'){
5101 before = el.nextSibling;
5104 node = ieTable(4, trs, html, tre);
5106 else if(tag == 'tr'){
5107 if(where == 'beforebegin'){
5110 node = ieTable(3, tbs, html, tbe);
5111 } else if(where == 'afterend'){
5112 before = el.nextSibling;
5114 node = ieTable(3, tbs, html, tbe);
5115 } else{ // INTO a TR
5116 if(where == 'afterbegin'){
5117 before = el.firstChild;
5119 node = ieTable(4, trs, html, tre);
5121 } else if(tag == 'tbody'){
5122 if(where == 'beforebegin'){
5125 node = ieTable(2, ts, html, te);
5126 } else if(where == 'afterend'){
5127 before = el.nextSibling;
5129 node = ieTable(2, ts, html, te);
5131 if(where == 'afterbegin'){
5132 before = el.firstChild;
5134 node = ieTable(3, tbs, html, tbe);
5137 if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
5140 if(where == 'afterbegin'){
5141 before = el.firstChild;
5143 node = ieTable(2, ts, html, te);
5145 el.insertBefore(node, before);
5149 // this is a bit like the react update code...
5152 var updateNode = function(from, to)
5154 // should we handle non-standard elements?
5156 if (from.nodeType != to.nodeType) {
5157 from.parentNode.replaceChild(to, from);
5160 if (from.nodeType == 3) {
5161 // assume it's text?!
5162 if (from.data == to.data) {
5165 from.data = to.data;
5169 // assume 'to' doesnt have '1/3 nodetypes!
5170 if (from.nodeType !=1 || from.tagName != to.tagName) {
5171 from.parentNode.replaceChild(to, from);
5174 // compare attributes
5175 var ar = Array.from(from.attributes);
5176 for(var i = 0; i< ar.length;i++) {
5177 if (to.hasAttribute(ar[i].name)) {
5180 from.removeAttribute(ar[i].name);
5183 for(var i = 0; i< ar.length;i++) {
5184 if (from.getAttribute(ar[i].name) == to.getAttribute(ar[i].name)) {
5187 from.setAttribute(ar[i].name, to.getAttribute(ar[i].name));
5190 var far = Array.from(from.childNodes);
5191 var tar = Array.from(to.childNodes);
5192 // if the lengths are different.. then it's probably a editable content change, rather than
5193 // a change of the block definition..
5194 if (from.innerHTML == to.innerHTML) {
5197 if (far.length != tar.length) {
5198 from.innerHTML = to.innerHTML;
5202 for(var i = 0; i < far.length; i++) {
5203 updateNode(far[i], tar[i]);
5212 /** True to force the use of DOM instead of html fragments @type Boolean */
5216 * Returns the markup for the passed Element(s) config
5217 * @param {Object} o The Dom object spec (and children)
5220 markup : function(o){
5221 return createHtml(o);
5225 * Applies a style specification to an element
5226 * @param {String/HTMLElement} el The element to apply styles to
5227 * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
5228 * a function which returns such a specification.
5230 applyStyles : function(el, styles){
5233 if(typeof styles == "string"){
5234 var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
5236 while ((matches = re.exec(styles)) != null){
5237 el.setStyle(matches[1], matches[2]);
5239 }else if (typeof styles == "object"){
5240 for (var style in styles){
5241 el.setStyle(style, styles[style]);
5243 }else if (typeof styles == "function"){
5244 Roo.DomHelper.applyStyles(el, styles.call());
5250 * Inserts an HTML fragment into the Dom
5251 * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
5252 * @param {HTMLElement} el The context element
5253 * @param {String} html The HTML fragmenet
5254 * @return {HTMLElement} The new node
5256 insertHtml : function(where, el, html){
5257 where = where.toLowerCase();
5258 if(el.insertAdjacentHTML){
5259 if(tableRe.test(el.tagName)){
5261 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
5267 el.insertAdjacentHTML('BeforeBegin', html);
5268 return el.previousSibling;
5270 el.insertAdjacentHTML('AfterBegin', html);
5271 return el.firstChild;
5273 el.insertAdjacentHTML('BeforeEnd', html);
5274 return el.lastChild;
5276 el.insertAdjacentHTML('AfterEnd', html);
5277 return el.nextSibling;
5279 throw 'Illegal insertion point -> "' + where + '"';
5281 var range = el.ownerDocument.createRange();
5285 range.setStartBefore(el);
5286 frag = range.createContextualFragment(html);
5287 el.parentNode.insertBefore(frag, el);
5288 return el.previousSibling;
5291 range.setStartBefore(el.firstChild);
5292 frag = range.createContextualFragment(html);
5293 el.insertBefore(frag, el.firstChild);
5294 return el.firstChild;
5296 el.innerHTML = html;
5297 return el.firstChild;
5301 range.setStartAfter(el.lastChild);
5302 frag = range.createContextualFragment(html);
5303 el.appendChild(frag);
5304 return el.lastChild;
5306 el.innerHTML = html;
5307 return el.lastChild;
5310 range.setStartAfter(el);
5311 frag = range.createContextualFragment(html);
5312 el.parentNode.insertBefore(frag, el.nextSibling);
5313 return el.nextSibling;
5315 throw 'Illegal insertion point -> "' + where + '"';
5319 * Creates new Dom element(s) and inserts them before el
5320 * @param {String/HTMLElement/Element} el The context element
5321 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5322 * @param {Boolean} returnElement (optional) true to return a Roo.Element
5323 * @return {HTMLElement/Roo.Element} The new node
5325 insertBefore : function(el, o, returnElement){
5326 return this.doInsert(el, o, returnElement, "beforeBegin");
5330 * Creates new Dom element(s) and inserts them after el
5331 * @param {String/HTMLElement/Element} el The context element
5332 * @param {Object} o The Dom object spec (and children)
5333 * @param {Boolean} returnElement (optional) true to return a Roo.Element
5334 * @return {HTMLElement/Roo.Element} The new node
5336 insertAfter : function(el, o, returnElement){
5337 return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
5341 * Creates new Dom element(s) and inserts them as the first child of el
5342 * @param {String/HTMLElement/Element} el The context element
5343 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5344 * @param {Boolean} returnElement (optional) true to return a Roo.Element
5345 * @return {HTMLElement/Roo.Element} The new node
5347 insertFirst : function(el, o, returnElement){
5348 return this.doInsert(el, o, returnElement, "afterBegin");
5352 doInsert : function(el, o, returnElement, pos, sibling){
5353 el = Roo.getDom(el);
5355 if(this.useDom || o.ns){
5356 newNode = createDom(o, null);
5357 el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
5359 var html = createHtml(o);
5360 newNode = this.insertHtml(pos, el, html);
5362 return returnElement ? Roo.get(newNode, true) : newNode;
5366 * Creates new Dom element(s) and appends them to el
5367 * @param {String/HTMLElement/Element} el The context element
5368 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5369 * @param {Boolean} returnElement (optional) true to return a Roo.Element
5370 * @return {HTMLElement/Roo.Element} The new node
5372 append : function(el, o, returnElement){
5373 el = Roo.getDom(el);
5375 if(this.useDom || o.ns){
5376 newNode = createDom(o, null);
5377 el.appendChild(newNode);
5379 var html = createHtml(o);
5380 newNode = this.insertHtml("beforeEnd", el, html);
5382 return returnElement ? Roo.get(newNode, true) : newNode;
5386 * Creates new Dom element(s) and overwrites the contents of el with them
5387 * @param {String/HTMLElement/Element} el The context element
5388 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5389 * @param {Boolean} returnElement (optional) true to return a Roo.Element
5390 * @return {HTMLElement/Roo.Element} The new node
5392 overwrite : function(el, o, returnElement)
5394 el = Roo.getDom(el);
5397 while (el.childNodes.length) {
5398 el.removeChild(el.firstChild);
5402 el.innerHTML = createHtml(o);
5405 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
5409 * Creates a new Roo.DomHelper.Template from the Dom object spec
5410 * @param {Object} o The Dom object spec (and children)
5411 * @return {Roo.DomHelper.Template} The new template
5413 createTemplate : function(o){
5414 var html = createHtml(o);
5415 return new Roo.Template(html);
5418 * Updates the first element with the spec from the o (replacing if necessary)
5419 * This iterates through the children, and updates attributes / children etc..
5420 * @param {String/HTMLElement/Element} el The context element
5421 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
5424 update : function(el, o)
5426 updateNode(Roo.getDom(el), createDom(o));
5435 * Ext JS Library 1.1.1
5436 * Copyright(c) 2006-2007, Ext JS, LLC.
5438 * Originally Released Under LGPL - original licence link has changed is not relivant.
5441 * <script type="text/javascript">
5445 * @class Roo.Template
5446 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
5447 * For a list of available format functions, see {@link Roo.util.Format}.<br />
5450 var t = new Roo.Template({
5451 html : '<div name="{id}">' +
5452 '<span class="{cls}">{name:trim} {someval:this.myformat}{value:ellipsis(10)}</span>' +
5454 myformat: function (value, allValues) {
5455 return 'XX' + value;
5458 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
5460 * For more information see this blog post with examples:
5461 * <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
5462 - Create Elements using DOM, HTML fragments and Templates</a>.
5464 * @param {Object} cfg - Configuration object.
5466 Roo.Template = function(cfg){
5468 if(cfg instanceof Array){
5470 }else if(arguments.length > 1){
5471 cfg = Array.prototype.join.call(arguments, "");
5475 if (typeof(cfg) == 'object') {
5486 Roo.Template.prototype = {
5489 * @cfg {Function} onLoad Called after the template has been loaded and complied (usually from a remove source)
5495 * @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..
5496 * it should be fixed so that template is observable...
5500 * @cfg {String} html The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
5508 * Returns an HTML fragment of this template with the specified values applied.
5509 * @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'})
5510 * @return {String} The HTML fragment
5515 applyTemplate : function(values){
5516 //Roo.log(["applyTemplate", values]);
5520 return this.compiled(values);
5522 var useF = this.disableFormats !== true;
5523 var fm = Roo.util.Format, tpl = this;
5524 var fn = function(m, name, format, args){
5526 if(format.substr(0, 5) == "this."){
5527 return tpl.call(format.substr(5), values[name], values);
5530 // quoted values are required for strings in compiled templates,
5531 // but for non compiled we need to strip them
5532 // quoted reversed for jsmin
5533 var re = /^\s*['"](.*)["']\s*$/;
5534 args = args.split(',');
5535 for(var i = 0, len = args.length; i < len; i++){
5536 args[i] = args[i].replace(re, "$1");
5538 args = [values[name]].concat(args);
5540 args = [values[name]];
5542 return fm[format].apply(fm, args);
5545 return values[name] !== undefined ? values[name] : "";
5548 return this.html.replace(this.re, fn);
5566 this.loading = true;
5567 this.compiled = false;
5569 var cx = new Roo.data.Connection();
5573 success : function (response) {
5577 _t.set(response.responseText,true);
5583 failure : function(response) {
5584 Roo.log("Template failed to load from " + _t.url);
5591 * Sets the HTML used as the template and optionally compiles it.
5592 * @param {String} html
5593 * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
5594 * @return {Roo.Template} this
5596 set : function(html, compile){
5598 this.compiled = false;
5606 * True to disable format functions (defaults to false)
5609 disableFormats : false,
5612 * The regular expression used to match template variables
5616 re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
5619 * Compiles the template into an internal function, eliminating the RegEx overhead.
5620 * @return {Roo.Template} this
5622 compile : function(){
5623 var fm = Roo.util.Format;
5624 var useF = this.disableFormats !== true;
5625 var sep = Roo.isGecko ? "+" : ",";
5626 var fn = function(m, name, format, args){
5628 args = args ? ',' + args : "";
5629 if(format.substr(0, 5) != "this."){
5630 format = "fm." + format + '(';
5632 format = 'this.call("'+ format.substr(5) + '", ';
5636 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
5638 return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
5641 // branched to use + in gecko and [].join() in others
5643 body = "this.compiled = function(values){ return '" +
5644 this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
5647 body = ["this.compiled = function(values){ return ['"];
5648 body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
5649 body.push("'].join('');};");
5650 body = body.join('');
5660 // private function used to call members
5661 call : function(fnName, value, allValues){
5662 return this[fnName](value, allValues);
5666 * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
5667 * @param {String/HTMLElement/Roo.Element} el The context element
5668 * @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'})
5669 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
5670 * @return {HTMLElement/Roo.Element} The new node or Element
5672 insertFirst: function(el, values, returnElement){
5673 return this.doInsert('afterBegin', el, values, returnElement);
5677 * Applies the supplied values to the template and inserts the new node(s) before el.
5678 * @param {String/HTMLElement/Roo.Element} el The context element
5679 * @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'})
5680 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
5681 * @return {HTMLElement/Roo.Element} The new node or Element
5683 insertBefore: function(el, values, returnElement){
5684 return this.doInsert('beforeBegin', el, values, returnElement);
5688 * Applies the supplied values to the template and inserts the new node(s) after el.
5689 * @param {String/HTMLElement/Roo.Element} el The context element
5690 * @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'})
5691 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
5692 * @return {HTMLElement/Roo.Element} The new node or Element
5694 insertAfter : function(el, values, returnElement){
5695 return this.doInsert('afterEnd', el, values, returnElement);
5699 * Applies the supplied values to the template and appends the new node(s) to el.
5700 * @param {String/HTMLElement/Roo.Element} el The context element
5701 * @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'})
5702 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
5703 * @return {HTMLElement/Roo.Element} The new node or Element
5705 append : function(el, values, returnElement){
5706 return this.doInsert('beforeEnd', el, values, returnElement);
5709 doInsert : function(where, el, values, returnEl){
5710 el = Roo.getDom(el);
5711 var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
5712 return returnEl ? Roo.get(newNode, true) : newNode;
5716 * Applies the supplied values to the template and overwrites the content of el with the new node(s).
5717 * @param {String/HTMLElement/Roo.Element} el The context element
5718 * @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'})
5719 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
5720 * @return {HTMLElement/Roo.Element} The new node or Element
5722 overwrite : function(el, values, returnElement){
5723 el = Roo.getDom(el);
5724 el.innerHTML = this.applyTemplate(values);
5725 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
5729 * Alias for {@link #applyTemplate}
5732 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
5735 Roo.DomHelper.Template = Roo.Template;
5738 * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
5739 * @param {String/HTMLElement} el A DOM element or its id
5740 * @returns {Roo.Template} The created template
5743 Roo.Template.from = function(el){
5744 el = Roo.getDom(el);
5745 return new Roo.Template(el.value || el.innerHTML);
5748 * Ext JS Library 1.1.1
5749 * Copyright(c) 2006-2007, Ext JS, LLC.
5751 * Originally Released Under LGPL - original licence link has changed is not relivant.
5754 * <script type="text/javascript">
5759 * This is code is also distributed under MIT license for use
5760 * with jQuery and prototype JavaScript libraries.
5763 * @class Roo.DomQuery
5764 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).
5766 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>
5769 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.
5771 <h4>Element Selectors:</h4>
5773 <li> <b>*</b> any element</li>
5774 <li> <b>E</b> an element with the tag E</li>
5775 <li> <b>E F</b> All descendent elements of E that have the tag F</li>
5776 <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
5777 <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
5778 <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
5780 <h4>Attribute Selectors:</h4>
5781 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
5783 <li> <b>E[foo]</b> has an attribute "foo"</li>
5784 <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
5785 <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
5786 <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
5787 <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
5788 <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
5789 <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
5791 <h4>Pseudo Classes:</h4>
5793 <li> <b>E:first-child</b> E is the first child of its parent</li>
5794 <li> <b>E:last-child</b> E is the last child of its parent</li>
5795 <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>
5796 <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
5797 <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
5798 <li> <b>E:only-child</b> E is the only child of its parent</li>
5799 <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>
5800 <li> <b>E:first</b> the first E in the resultset</li>
5801 <li> <b>E:last</b> the last E in the resultset</li>
5802 <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
5803 <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
5804 <li> <b>E:even</b> shortcut for :nth-child(even)</li>
5805 <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
5806 <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
5807 <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
5808 <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
5809 <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
5810 <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
5812 <h4>CSS Value Selectors:</h4>
5814 <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
5815 <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
5816 <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
5817 <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
5818 <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
5819 <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
5823 Roo.DomQuery = function(){
5824 var cache = {}, simpleCache = {}, valueCache = {};
5825 var nonSpace = /\S/;
5826 var trimRe = /^\s+|\s+$/g;
5827 var tplRe = /\{(\d+)\}/g;
5828 var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
5829 var tagTokenRe = /^(#)?([\w-\*]+)/;
5830 var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
5832 function child(p, index){
5834 var n = p.firstChild;
5836 if(n.nodeType == 1){
5847 while((n = n.nextSibling) && n.nodeType != 1);
5852 while((n = n.previousSibling) && n.nodeType != 1);
5856 function children(d){
5857 var n = d.firstChild, ni = -1;
5859 var nx = n.nextSibling;
5860 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
5870 function byClassName(c, a, v){
5874 var r = [], ri = -1, cn;
5875 for(var i = 0, ci; ci = c[i]; i++){
5879 ( (ci instanceof SVGElement) ? ci.className.baseVal : ci.className)
5880 +' ').indexOf(v) != -1){
5887 function attrValue(n, attr){
5888 if(!n.tagName && typeof n.length != "undefined"){
5897 if(attr == "class" || attr == "className"){
5898 return (n instanceof SVGElement) ? n.className.baseVal : n.className;
5900 return n.getAttribute(attr) || n[attr];
5904 function getNodes(ns, mode, tagName){
5905 var result = [], ri = -1, cs;
5909 tagName = tagName || "*";
5910 if(typeof ns.getElementsByTagName != "undefined"){
5914 for(var i = 0, ni; ni = ns[i]; i++){
5915 cs = ni.getElementsByTagName(tagName);
5916 for(var j = 0, ci; ci = cs[j]; j++){
5920 }else if(mode == "/" || mode == ">"){
5921 var utag = tagName.toUpperCase();
5922 for(var i = 0, ni, cn; ni = ns[i]; i++){
5923 cn = ni.children || ni.childNodes;
5924 for(var j = 0, cj; cj = cn[j]; j++){
5925 if(cj.nodeName == utag || cj.nodeName == tagName || tagName == '*'){
5930 }else if(mode == "+"){
5931 var utag = tagName.toUpperCase();
5932 for(var i = 0, n; n = ns[i]; i++){
5933 while((n = n.nextSibling) && n.nodeType != 1);
5934 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5938 }else if(mode == "~"){
5939 for(var i = 0, n; n = ns[i]; i++){
5940 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5949 function concat(a, b){
5953 for(var i = 0, l = b.length; i < l; i++){
5959 function byTag(cs, tagName){
5960 if(cs.tagName || cs == document){
5966 var r = [], ri = -1;
5967 tagName = tagName.toLowerCase();
5968 for(var i = 0, ci; ci = cs[i]; i++){
5969 if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5976 function byId(cs, attr, id){
5977 if(cs.tagName || cs == document){
5983 var r = [], ri = -1;
5984 for(var i = 0,ci; ci = cs[i]; i++){
5985 if(ci && ci.id == id){
5993 function byAttribute(cs, attr, value, op, custom){
5994 var r = [], ri = -1, st = custom=="{";
5995 var f = Roo.DomQuery.operators[op];
5996 for(var i = 0, ci; ci = cs[i]; i++){
5999 a = Roo.DomQuery.getStyle(ci, attr);
6001 else if(attr == "class" || attr == "className"){
6002 a = (ci instanceof SVGElement) ? ci.className.baseVal : ci.className;
6003 }else if(attr == "for"){
6005 }else if(attr == "href"){
6006 a = ci.getAttribute("href", 2);
6008 a = ci.getAttribute(attr);
6010 if((f && f(a, value)) || (!f && a)){
6017 function byPseudo(cs, name, value){
6018 return Roo.DomQuery.pseudos[name](cs, value);
6021 // This is for IE MSXML which does not support expandos.
6022 // IE runs the same speed using setAttribute, however FF slows way down
6023 // and Safari completely fails so they need to continue to use expandos.
6024 var isIE = window.ActiveXObject ? true : false;
6026 // this eval is stop the compressor from
6027 // renaming the variable to something shorter
6029 /** eval:var:batch */
6034 function nodupIEXml(cs){
6036 cs[0].setAttribute("_nodup", d);
6038 for(var i = 1, len = cs.length; i < len; i++){
6040 if(!c.getAttribute("_nodup") != d){
6041 c.setAttribute("_nodup", d);
6045 for(var i = 0, len = cs.length; i < len; i++){
6046 cs[i].removeAttribute("_nodup");
6055 var len = cs.length, c, i, r = cs, cj, ri = -1;
6056 if(!len || typeof cs.nodeType != "undefined" || len == 1){
6059 if(isIE && typeof cs[0].selectSingleNode != "undefined"){
6060 return nodupIEXml(cs);
6064 for(i = 1; c = cs[i]; i++){
6069 for(var j = 0; j < i; j++){
6072 for(j = i+1; cj = cs[j]; j++){
6084 function quickDiffIEXml(c1, c2){
6086 for(var i = 0, len = c1.length; i < len; i++){
6087 c1[i].setAttribute("_qdiff", d);
6090 for(var i = 0, len = c2.length; i < len; i++){
6091 if(c2[i].getAttribute("_qdiff") != d){
6092 r[r.length] = c2[i];
6095 for(var i = 0, len = c1.length; i < len; i++){
6096 c1[i].removeAttribute("_qdiff");
6101 function quickDiff(c1, c2){
6102 var len1 = c1.length;
6106 if(isIE && c1[0].selectSingleNode){
6107 return quickDiffIEXml(c1, c2);
6110 for(var i = 0; i < len1; i++){
6114 for(var i = 0, len = c2.length; i < len; i++){
6115 if(c2[i]._qdiff != d){
6116 r[r.length] = c2[i];
6122 function quickId(ns, mode, root, id){
6124 var d = root.ownerDocument || root;
6125 return d.getElementById(id);
6127 ns = getNodes(ns, mode, "*");
6128 return byId(ns, null, id);
6132 getStyle : function(el, name){
6133 return Roo.fly(el).getStyle(name);
6136 * Compiles a selector/xpath query into a reusable function. The returned function
6137 * takes one parameter "root" (optional), which is the context node from where the query should start.
6138 * @param {String} selector The selector/xpath query
6139 * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
6140 * @return {Function}
6142 compile : function(path, type){
6143 type = type || "select";
6145 var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
6146 var q = path, mode, lq;
6147 var tk = Roo.DomQuery.matchers;
6148 var tklen = tk.length;
6151 // accept leading mode switch
6152 var lmode = q.match(modeRe);
6153 if(lmode && lmode[1]){
6154 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
6155 q = q.replace(lmode[1], "");
6157 // strip leading slashes
6158 while(path.substr(0, 1)=="/"){
6159 path = path.substr(1);
6162 while(q && lq != q){
6164 var tm = q.match(tagTokenRe);
6165 if(type == "select"){
6168 fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
6170 fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
6172 q = q.replace(tm[0], "");
6173 }else if(q.substr(0, 1) != '@'){
6174 fn[fn.length] = 'n = getNodes(n, mode, "*");';
6179 fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
6181 fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
6183 q = q.replace(tm[0], "");
6186 while(!(mm = q.match(modeRe))){
6187 var matched = false;
6188 for(var j = 0; j < tklen; j++){
6190 var m = q.match(t.re);
6192 fn[fn.length] = t.select.replace(tplRe, function(x, i){
6195 q = q.replace(m[0], "");
6200 // prevent infinite loop on bad selector
6202 throw 'Error parsing selector, parsing failed at "' + q + '"';
6206 fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
6207 q = q.replace(mm[1], "");
6210 fn[fn.length] = "return nodup(n);\n}";
6213 * list of variables that need from compression as they are used by eval.
6223 * eval:var:byClassName
6225 * eval:var:byAttribute
6226 * eval:var:attrValue
6234 * Selects a group of elements.
6235 * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
6236 * @param {Node} root (optional) The start of the query (defaults to document).
6239 select : function(path, root, type){
6240 if(!root || root == document){
6243 if(typeof root == "string"){
6244 root = document.getElementById(root);
6246 var paths = path.split(",");
6248 for(var i = 0, len = paths.length; i < len; i++){
6249 var p = paths[i].replace(trimRe, "");
6251 cache[p] = Roo.DomQuery.compile(p);
6253 throw p + " is not a valid selector";
6256 var result = cache[p](root);
6257 if(result && result != document){
6258 results = results.concat(result);
6261 if(paths.length > 1){
6262 return nodup(results);
6268 * Selects a single element.
6269 * @param {String} selector The selector/xpath query
6270 * @param {Node} root (optional) The start of the query (defaults to document).
6273 selectNode : function(path, root){
6274 return Roo.DomQuery.select(path, root)[0];
6278 * Selects the value of a node, optionally replacing null with the defaultValue.
6279 * @param {String} selector The selector/xpath query
6280 * @param {Node} root (optional) The start of the query (defaults to document).
6281 * @param {String} defaultValue
6283 selectValue : function(path, root, defaultValue){
6284 path = path.replace(trimRe, "");
6285 if(!valueCache[path]){
6286 valueCache[path] = Roo.DomQuery.compile(path, "select");
6288 var n = valueCache[path](root);
6289 n = n[0] ? n[0] : n;
6290 var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
6291 return ((v === null||v === undefined||v==='') ? defaultValue : v);
6295 * Selects the value of a node, parsing integers and floats.
6296 * @param {String} selector The selector/xpath query
6297 * @param {Node} root (optional) The start of the query (defaults to document).
6298 * @param {Number} defaultValue
6301 selectNumber : function(path, root, defaultValue){
6302 var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
6303 return parseFloat(v);
6307 * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
6308 * @param {String/HTMLElement/Array} el An element id, element or array of elements
6309 * @param {String} selector The simple selector to test
6312 is : function(el, ss){
6313 if(typeof el == "string"){
6314 el = document.getElementById(el);
6316 var isArray = (el instanceof Array);
6317 var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
6318 return isArray ? (result.length == el.length) : (result.length > 0);
6322 * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
6323 * @param {Array} el An array of elements to filter
6324 * @param {String} selector The simple selector to test
6325 * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
6326 * the selector instead of the ones that match
6329 filter : function(els, ss, nonMatches){
6330 ss = ss.replace(trimRe, "");
6331 if(!simpleCache[ss]){
6332 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
6334 var result = simpleCache[ss](els);
6335 return nonMatches ? quickDiff(result, els) : result;
6339 * Collection of matching regular expressions and code snippets.
6343 select: 'n = byClassName(n, null, " {1} ");'
6345 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
6346 select: 'n = byPseudo(n, "{1}", "{2}");'
6348 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
6349 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
6352 select: 'n = byId(n, null, "{1}");'
6355 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
6360 * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
6361 * 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, > <.
6364 "=" : function(a, v){
6367 "!=" : function(a, v){
6370 "^=" : function(a, v){
6371 return a && a.substr(0, v.length) == v;
6373 "$=" : function(a, v){
6374 return a && a.substr(a.length-v.length) == v;
6376 "*=" : function(a, v){
6377 return a && a.indexOf(v) !== -1;
6379 "%=" : function(a, v){
6380 return (a % v) == 0;
6382 "|=" : function(a, v){
6383 return a && (a == v || a.substr(0, v.length+1) == v+'-');
6385 "~=" : function(a, v){
6386 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
6391 * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
6392 * and the argument (if any) supplied in the selector.
6395 "first-child" : function(c){
6396 var r = [], ri = -1, n;
6397 for(var i = 0, ci; ci = n = c[i]; i++){
6398 while((n = n.previousSibling) && n.nodeType != 1);
6406 "last-child" : function(c){
6407 var r = [], ri = -1, n;
6408 for(var i = 0, ci; ci = n = c[i]; i++){
6409 while((n = n.nextSibling) && n.nodeType != 1);
6417 "nth-child" : function(c, a) {
6418 var r = [], ri = -1;
6419 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
6420 var f = (m[1] || 1) - 0, l = m[2] - 0;
6421 for(var i = 0, n; n = c[i]; i++){
6422 var pn = n.parentNode;
6423 if (batch != pn._batch) {
6425 for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
6426 if(cn.nodeType == 1){
6433 if (l == 0 || n.nodeIndex == l){
6436 } else if ((n.nodeIndex + l) % f == 0){
6444 "only-child" : function(c){
6445 var r = [], ri = -1;;
6446 for(var i = 0, ci; ci = c[i]; i++){
6447 if(!prev(ci) && !next(ci)){
6454 "empty" : function(c){
6455 var r = [], ri = -1;
6456 for(var i = 0, ci; ci = c[i]; i++){
6457 var cns = ci.childNodes, j = 0, cn, empty = true;
6460 if(cn.nodeType == 1 || cn.nodeType == 3){
6472 "contains" : function(c, v){
6473 var r = [], ri = -1;
6474 for(var i = 0, ci; ci = c[i]; i++){
6475 if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
6482 "nodeValue" : function(c, v){
6483 var r = [], ri = -1;
6484 for(var i = 0, ci; ci = c[i]; i++){
6485 if(ci.firstChild && ci.firstChild.nodeValue == v){
6492 "checked" : function(c){
6493 var r = [], ri = -1;
6494 for(var i = 0, ci; ci = c[i]; i++){
6495 if(ci.checked == true){
6502 "not" : function(c, ss){
6503 return Roo.DomQuery.filter(c, ss, true);
6506 "odd" : function(c){
6507 return this["nth-child"](c, "odd");
6510 "even" : function(c){
6511 return this["nth-child"](c, "even");
6514 "nth" : function(c, a){
6515 return c[a-1] || [];
6518 "first" : function(c){
6522 "last" : function(c){
6523 return c[c.length-1] || [];
6526 "has" : function(c, ss){
6527 var s = Roo.DomQuery.select;
6528 var r = [], ri = -1;
6529 for(var i = 0, ci; ci = c[i]; i++){
6530 if(s(ss, ci).length > 0){
6537 "next" : function(c, ss){
6538 var is = Roo.DomQuery.is;
6539 var r = [], ri = -1;
6540 for(var i = 0, ci; ci = c[i]; i++){
6549 "prev" : function(c, ss){
6550 var is = Roo.DomQuery.is;
6551 var r = [], ri = -1;
6552 for(var i = 0, ci; ci = c[i]; i++){
6565 * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
6566 * @param {String} path The selector/xpath query
6567 * @param {Node} root (optional) The start of the query (defaults to document).
6572 Roo.query = Roo.DomQuery.select;
6575 * Ext JS Library 1.1.1
6576 * Copyright(c) 2006-2007, Ext JS, LLC.
6578 * Originally Released Under LGPL - original licence link has changed is not relivant.
6581 * <script type="text/javascript">
6585 * @class Roo.util.Observable
6586 * Base class that provides a common interface for publishing events. Subclasses are expected to
6587 * to have a property "events" with all the events defined.<br>
6590 Employee = function(name){
6597 Roo.extend(Employee, Roo.util.Observable);
6599 * @param {Object} config properties to use (incuding events / listeners)
6602 Roo.util.Observable = function(cfg){
6605 this.addEvents(cfg.events || {});
6607 delete cfg.events; // make sure
6610 Roo.apply(this, cfg);
6613 this.on(this.listeners);
6614 delete this.listeners;
6617 Roo.util.Observable.prototype = {
6619 * @cfg {Object} listeners list of events and functions to call for this object,
6623 'click' : function(e) {
6633 * Fires the specified event with the passed parameters (minus the event name).
6634 * @param {String} eventName
6635 * @param {Object...} args Variable number of parameters are passed to handlers
6636 * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
6638 fireEvent : function(){
6639 var ce = this.events[arguments[0].toLowerCase()];
6640 if(typeof ce == "object"){
6641 return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
6648 filterOptRe : /^(?:scope|delay|buffer|single)$/,
6651 * Appends an event handler to this component
6652 * @param {String} eventName The type of event to listen for
6653 * @param {Function} handler The method the event invokes
6654 * @param {Object} scope (optional) The scope in which to execute the handler
6655 * function. The handler function's "this" context.
6656 * @param {Object} options (optional) An object containing handler configuration
6657 * properties. This may contain any of the following properties:<ul>
6658 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6659 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6660 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6661 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6662 * by the specified number of milliseconds. If the event fires again within that time, the original
6663 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6666 * <b>Combining Options</b><br>
6667 * Using the options argument, it is possible to combine different types of listeners:<br>
6669 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
6671 el.on('click', this.onClick, this, {
6678 * <b>Attaching multiple handlers in 1 call</b><br>
6679 * The method also allows for a single argument to be passed which is a config object containing properties
6680 * which specify multiple handlers.
6689 fn: this.onMouseOver,
6693 fn: this.onMouseOut,
6699 * Or a shorthand syntax which passes the same scope object to all handlers:
6702 'click': this.onClick,
6703 'mouseover': this.onMouseOver,
6704 'mouseout': this.onMouseOut,
6709 addListener : function(eventName, fn, scope, o){
6710 if(typeof eventName == "object"){
6713 if(this.filterOptRe.test(e)){
6716 if(typeof o[e] == "function"){
6718 this.addListener(e, o[e], o.scope, o);
6720 // individual options
6721 this.addListener(e, o[e].fn, o[e].scope, o[e]);
6726 o = (!o || typeof o == "boolean") ? {} : o;
6727 eventName = eventName.toLowerCase();
6728 var ce = this.events[eventName] || true;
6729 if(typeof ce == "boolean"){
6730 ce = new Roo.util.Event(this, eventName);
6731 this.events[eventName] = ce;
6733 ce.addListener(fn, scope, o);
6737 * Removes a listener
6738 * @param {String} eventName The type of event to listen for
6739 * @param {Function} handler The handler to remove
6740 * @param {Object} scope (optional) The scope (this object) for the handler
6742 removeListener : function(eventName, fn, scope){
6743 var ce = this.events[eventName.toLowerCase()];
6744 if(typeof ce == "object"){
6745 ce.removeListener(fn, scope);
6750 * Removes all listeners for this object
6752 purgeListeners : function(){
6753 for(var evt in this.events){
6754 if(typeof this.events[evt] == "object"){
6755 this.events[evt].clearListeners();
6760 relayEvents : function(o, events){
6761 var createHandler = function(ename){
6764 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
6767 for(var i = 0, len = events.length; i < len; i++){
6768 var ename = events[i];
6769 if(!this.events[ename]){
6770 this.events[ename] = true;
6772 o.on(ename, createHandler(ename), this);
6777 * Used to define events on this Observable
6778 * @param {Object} object The object with the events defined
6780 addEvents : function(o){
6784 Roo.applyIf(this.events, o);
6788 * Checks to see if this object has any listeners for a specified event
6789 * @param {String} eventName The name of the event to check for
6790 * @return {Boolean} True if the event is being listened for, else false
6792 hasListener : function(eventName){
6793 var e = this.events[eventName];
6794 return typeof e == "object" && e.listeners.length > 0;
6798 * Appends an event handler to this element (shorthand for addListener)
6799 * @param {String} eventName The type of event to listen for
6800 * @param {Function} handler The method the event invokes
6801 * @param {Object} scope (optional) The scope in which to execute the handler
6802 * function. The handler function's "this" context.
6803 * @param {Object} options (optional)
6806 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
6808 * Removes a listener (shorthand for removeListener)
6809 * @param {String} eventName The type of event to listen for
6810 * @param {Function} handler The handler to remove
6811 * @param {Object} scope (optional) The scope (this object) for the handler
6814 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
6817 * Starts capture on the specified Observable. All events will be passed
6818 * to the supplied function with the event name + standard signature of the event
6819 * <b>before</b> the event is fired. If the supplied function returns false,
6820 * the event will not fire.
6821 * @param {Observable} o The Observable to capture
6822 * @param {Function} fn The function to call
6823 * @param {Object} scope (optional) The scope (this object) for the fn
6826 Roo.util.Observable.capture = function(o, fn, scope){
6827 o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
6831 * Removes <b>all</b> added captures from the Observable.
6832 * @param {Observable} o The Observable to release
6835 Roo.util.Observable.releaseCapture = function(o){
6836 o.fireEvent = Roo.util.Observable.prototype.fireEvent;
6841 var createBuffered = function(h, o, scope){
6842 var task = new Roo.util.DelayedTask();
6844 task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
6848 var createSingle = function(h, e, fn, scope){
6850 e.removeListener(fn, scope);
6851 return h.apply(scope, arguments);
6855 var createDelayed = function(h, o, scope){
6857 var args = Array.prototype.slice.call(arguments, 0);
6858 setTimeout(function(){
6859 h.apply(scope, args);
6864 Roo.util.Event = function(obj, name){
6867 this.listeners = [];
6870 Roo.util.Event.prototype = {
6871 addListener : function(fn, scope, options){
6872 var o = options || {};
6873 scope = scope || this.obj;
6874 if(!this.isListening(fn, scope)){
6875 var l = {fn: fn, scope: scope, options: o};
6878 h = createDelayed(h, o, scope);
6881 h = createSingle(h, this, fn, scope);
6884 h = createBuffered(h, o, scope);
6887 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
6888 this.listeners.push(l);
6890 this.listeners = this.listeners.slice(0);
6891 this.listeners.push(l);
6896 findListener : function(fn, scope){
6897 scope = scope || this.obj;
6898 var ls = this.listeners;
6899 for(var i = 0, len = ls.length; i < len; i++){
6901 if(l.fn == fn && l.scope == scope){
6908 isListening : function(fn, scope){
6909 return this.findListener(fn, scope) != -1;
6912 removeListener : function(fn, scope){
6914 if((index = this.findListener(fn, scope)) != -1){
6916 this.listeners.splice(index, 1);
6918 this.listeners = this.listeners.slice(0);
6919 this.listeners.splice(index, 1);
6926 clearListeners : function(){
6927 this.listeners = [];
6931 var ls = this.listeners, scope, len = ls.length;
6934 var args = Array.prototype.slice.call(arguments, 0);
6935 for(var i = 0; i < len; i++){
6937 if(l.fireFn.apply(l.scope||this.obj||window, args) === false){
6938 this.firing = false;
6942 this.firing = false;
6949 * Copyright(c) 2007-2017, Roo J Solutions Ltd
6956 * @class Roo.Document
6957 * @extends Roo.util.Observable
6958 * This is a convience class to wrap up the main document loading code.. , rather than adding Roo.onReady(......)
6960 * @param {Object} config the methods and properties of the 'base' class for the application.
6962 * Generic Page handler - implement this to start your app..
6965 * MyProject = new Roo.Document({
6967 'load' : true // your events..
6970 'ready' : function() {
6971 // fired on Roo.onReady()
6976 Roo.Document = function(cfg) {
6981 Roo.util.Observable.call(this,cfg);
6985 Roo.onReady(function() {
6986 _this.fireEvent('ready');
6992 Roo.extend(Roo.Document, Roo.util.Observable, {});/*
6994 * Ext JS Library 1.1.1
6995 * Copyright(c) 2006-2007, Ext JS, LLC.
6997 * Originally Released Under LGPL - original licence link has changed is not relivant.
7000 * <script type="text/javascript">
7004 * @class Roo.EventManager
7005 * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
7006 * several useful events directly.
7007 * See {@link Roo.EventObject} for more details on normalized event objects.
7010 Roo.EventManager = function(){
7011 var docReadyEvent, docReadyProcId, docReadyState = false;
7012 var resizeEvent, resizeTask, textEvent, textSize;
7013 var E = Roo.lib.Event;
7014 var D = Roo.lib.Dom;
7019 var fireDocReady = function(){
7021 docReadyState = true;
7024 clearInterval(docReadyProcId);
7026 if(Roo.isGecko || Roo.isOpera) {
7027 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
7030 var defer = document.getElementById("ie-deferred-loader");
7032 defer.onreadystatechange = null;
7033 defer.parentNode.removeChild(defer);
7037 docReadyEvent.fire();
7038 docReadyEvent.clearListeners();
7043 var initDocReady = function(){
7044 docReadyEvent = new Roo.util.Event();
7045 if(Roo.isGecko || Roo.isOpera) {
7046 document.addEventListener("DOMContentLoaded", fireDocReady, false);
7048 document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
7049 var defer = document.getElementById("ie-deferred-loader");
7050 defer.onreadystatechange = function(){
7051 if(this.readyState == "complete"){
7055 }else if(Roo.isSafari){
7056 docReadyProcId = setInterval(function(){
7057 var rs = document.readyState;
7058 if(rs == "complete") {
7063 // no matter what, make sure it fires on load
7064 E.on(window, "load", fireDocReady);
7067 var createBuffered = function(h, o){
7068 var task = new Roo.util.DelayedTask(h);
7070 // create new event object impl so new events don't wipe out properties
7071 e = new Roo.EventObjectImpl(e);
7072 task.delay(o.buffer, h, null, [e]);
7076 var createSingle = function(h, el, ename, fn){
7078 Roo.EventManager.removeListener(el, ename, fn);
7083 var createDelayed = function(h, o){
7085 // create new event object impl so new events don't wipe out properties
7086 e = new Roo.EventObjectImpl(e);
7087 setTimeout(function(){
7092 var transitionEndVal = false;
7094 var transitionEnd = function()
7096 if (transitionEndVal) {
7097 return transitionEndVal;
7099 var el = document.createElement('div');
7101 var transEndEventNames = {
7102 WebkitTransition : 'webkitTransitionEnd',
7103 MozTransition : 'transitionend',
7104 OTransition : 'oTransitionEnd otransitionend',
7105 transition : 'transitionend'
7108 for (var name in transEndEventNames) {
7109 if (el.style[name] !== undefined) {
7110 transitionEndVal = transEndEventNames[name];
7111 return transitionEndVal ;
7118 var listen = function(element, ename, opt, fn, scope)
7120 var o = (!opt || typeof opt == "boolean") ? {} : opt;
7121 fn = fn || o.fn; scope = scope || o.scope;
7122 var el = Roo.getDom(element);
7126 throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
7129 if (ename == 'transitionend') {
7130 ename = transitionEnd();
7132 var h = function(e){
7133 e = Roo.EventObject.setEvent(e);
7136 t = e.getTarget(o.delegate, el);
7143 if(o.stopEvent === true){
7146 if(o.preventDefault === true){
7149 if(o.stopPropagation === true){
7150 e.stopPropagation();
7153 if(o.normalized === false){
7157 fn.call(scope || el, e, t, o);
7160 h = createDelayed(h, o);
7163 h = createSingle(h, el, ename, fn);
7166 h = createBuffered(h, o);
7169 fn._handlers = fn._handlers || [];
7172 fn._handlers.push([Roo.id(el), ename, h]);
7176 E.on(el, ename, h); // this adds the actuall listener to the object..
7179 if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
7180 el.addEventListener("DOMMouseScroll", h, false);
7181 E.on(window, 'unload', function(){
7182 el.removeEventListener("DOMMouseScroll", h, false);
7185 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
7186 Roo.EventManager.stoppedMouseDownEvent.addListener(h);
7191 var stopListening = function(el, ename, fn){
7192 var id = Roo.id(el), hds = fn._handlers, hd = fn;
7194 for(var i = 0, len = hds.length; i < len; i++){
7196 if(h[0] == id && h[1] == ename){
7203 E.un(el, ename, hd);
7204 el = Roo.getDom(el);
7205 if(ename == "mousewheel" && el.addEventListener){
7206 el.removeEventListener("DOMMouseScroll", hd, false);
7208 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
7209 Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
7213 var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
7220 * @scope Roo.EventManager
7225 * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
7226 * object with a Roo.EventObject
7227 * @param {Function} fn The method the event invokes
7228 * @param {Object} scope An object that becomes the scope of the handler
7229 * @param {boolean} override If true, the obj passed in becomes
7230 * the execution scope of the listener
7231 * @return {Function} The wrapped function
7234 wrap : function(fn, scope, override){
7236 Roo.EventObject.setEvent(e);
7237 fn.call(override ? scope || window : window, Roo.EventObject, scope);
7242 * Appends an event handler to an element (shorthand for addListener)
7243 * @param {String/HTMLElement} element The html element or id to assign the
7244 * @param {String} eventName The type of event to listen for
7245 * @param {Function} handler The method the event invokes
7246 * @param {Object} scope (optional) The scope in which to execute the handler
7247 * function. The handler function's "this" context.
7248 * @param {Object} options (optional) An object containing handler configuration
7249 * properties. This may contain any of the following properties:<ul>
7250 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
7251 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
7252 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
7253 * <li>preventDefault {Boolean} True to prevent the default action</li>
7254 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
7255 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
7256 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
7257 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
7258 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
7259 * by the specified number of milliseconds. If the event fires again within that time, the original
7260 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
7263 * <b>Combining Options</b><br>
7264 * Using the options argument, it is possible to combine different types of listeners:<br>
7266 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
7268 el.on('click', this.onClick, this, {
7275 * <b>Attaching multiple handlers in 1 call</b><br>
7276 * The method also allows for a single argument to be passed which is a config object containing properties
7277 * which specify multiple handlers.
7287 fn: this.onMouseOver
7296 * Or a shorthand syntax:<br>
7299 'click' : this.onClick,
7300 'mouseover' : this.onMouseOver,
7301 'mouseout' : this.onMouseOut
7305 addListener : function(element, eventName, fn, scope, options){
7306 if(typeof eventName == "object"){
7312 if(typeof o[e] == "function"){
7314 listen(element, e, o, o[e], o.scope);
7316 // individual options
7317 listen(element, e, o[e]);
7322 return listen(element, eventName, options, fn, scope);
7326 * Removes an event handler
7328 * @param {String/HTMLElement} element The id or html element to remove the
7330 * @param {String} eventName The type of event
7331 * @param {Function} fn
7332 * @return {Boolean} True if a listener was actually removed
7334 removeListener : function(element, eventName, fn){
7335 return stopListening(element, eventName, fn);
7339 * Fires when the document is ready (before onload and before images are loaded). Can be
7340 * accessed shorthanded Roo.onReady().
7341 * @param {Function} fn The method the event invokes
7342 * @param {Object} scope An object that becomes the scope of the handler
7343 * @param {boolean} options
7345 onDocumentReady : function(fn, scope, options){
7346 if(docReadyState){ // if it already fired
7347 docReadyEvent.addListener(fn, scope, options);
7348 docReadyEvent.fire();
7349 docReadyEvent.clearListeners();
7355 docReadyEvent.addListener(fn, scope, options);
7359 * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
7360 * @param {Function} fn The method the event invokes
7361 * @param {Object} scope An object that becomes the scope of the handler
7362 * @param {boolean} options
7364 onWindowResize : function(fn, scope, options)
7367 resizeEvent = new Roo.util.Event();
7368 resizeTask = new Roo.util.DelayedTask(function(){
7369 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
7371 E.on(window, "resize", function()
7374 resizeTask.delay(50);
7376 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
7380 resizeEvent.addListener(fn, scope, options);
7384 * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
7385 * @param {Function} fn The method the event invokes
7386 * @param {Object} scope An object that becomes the scope of the handler
7387 * @param {boolean} options
7389 onTextResize : function(fn, scope, options){
7391 textEvent = new Roo.util.Event();
7392 var textEl = new Roo.Element(document.createElement('div'));
7393 textEl.dom.className = 'x-text-resize';
7394 textEl.dom.innerHTML = 'X';
7395 textEl.appendTo(document.body);
7396 textSize = textEl.dom.offsetHeight;
7397 setInterval(function(){
7398 if(textEl.dom.offsetHeight != textSize){
7399 textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
7401 }, this.textResizeInterval);
7403 textEvent.addListener(fn, scope, options);
7407 * Removes the passed window resize listener.
7408 * @param {Function} fn The method the event invokes
7409 * @param {Object} scope The scope of handler
7411 removeResizeListener : function(fn, scope){
7413 resizeEvent.removeListener(fn, scope);
7418 fireResize : function(){
7420 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
7424 * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
7428 * The frequency, in milliseconds, to check for text resize events (defaults to 50)
7430 textResizeInterval : 50
7435 * @scopeAlias pub=Roo.EventManager
7439 * Appends an event handler to an element (shorthand for addListener)
7440 * @param {String/HTMLElement} element The html element or id to assign the
7441 * @param {String} eventName The type of event to listen for
7442 * @param {Function} handler The method the event invokes
7443 * @param {Object} scope (optional) The scope in which to execute the handler
7444 * function. The handler function's "this" context.
7445 * @param {Object} options (optional) An object containing handler configuration
7446 * properties. This may contain any of the following properties:<ul>
7447 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
7448 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
7449 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
7450 * <li>preventDefault {Boolean} True to prevent the default action</li>
7451 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
7452 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
7453 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
7454 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
7455 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
7456 * by the specified number of milliseconds. If the event fires again within that time, the original
7457 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
7460 * <b>Combining Options</b><br>
7461 * Using the options argument, it is possible to combine different types of listeners:<br>
7463 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
7465 el.on('click', this.onClick, this, {
7472 * <b>Attaching multiple handlers in 1 call</b><br>
7473 * The method also allows for a single argument to be passed which is a config object containing properties
7474 * which specify multiple handlers.
7484 fn: this.onMouseOver
7493 * Or a shorthand syntax:<br>
7496 'click' : this.onClick,
7497 'mouseover' : this.onMouseOver,
7498 'mouseout' : this.onMouseOut
7502 pub.on = pub.addListener;
7503 pub.un = pub.removeListener;
7505 pub.stoppedMouseDownEvent = new Roo.util.Event();
7509 * Fires when the document is ready (before onload and before images are loaded). Shorthand of {@link Roo.EventManager#onDocumentReady}.
7510 * @param {Function} fn The method the event invokes
7511 * @param {Object} scope An object that becomes the scope of the handler
7512 * @param {boolean} override If true, the obj passed in becomes
7513 * the execution scope of the listener
7517 Roo.onReady = Roo.EventManager.onDocumentReady;
7519 Roo.onReady(function(){
7520 var bd = Roo.get(document.body);
7525 : Roo.isIE11 ? "roo-ie11"
7526 : Roo.isEdge ? "roo-edge"
7527 : Roo.isGecko ? "roo-gecko"
7528 : Roo.isOpera ? "roo-opera"
7529 : Roo.isSafari ? "roo-safari" : ""];
7532 cls.push("roo-mac");
7535 cls.push("roo-linux");
7538 cls.push("roo-ios");
7541 cls.push("roo-touch");
7543 if(Roo.isBorderBox){
7544 cls.push('roo-border-box');
7546 if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
7547 var p = bd.dom.parentNode;
7549 p.className += ' roo-strict';
7552 bd.addClass(cls.join(' '));
7556 * @class Roo.EventObject
7557 * EventObject exposes the Yahoo! UI Event functionality directly on the object
7558 * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code
7561 function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
7563 var target = e.getTarget();
7566 var myDiv = Roo.get("myDiv");
7567 myDiv.on("click", handleClick);
7569 Roo.EventManager.on("myDiv", 'click', handleClick);
7570 Roo.EventManager.addListener("myDiv", 'click', handleClick);
7574 Roo.EventObject = function(){
7576 var E = Roo.lib.Event;
7578 // safari keypress events for special keys return bad keycodes
7581 63235 : 39, // right
7584 63276 : 33, // page up
7585 63277 : 34, // page down
7586 63272 : 46, // delete
7591 // normalize button clicks
7592 var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
7593 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
7595 Roo.EventObjectImpl = function(e){
7597 this.setEvent(e.browserEvent || e);
7600 Roo.EventObjectImpl.prototype = {
7602 * Used to fix doc tools.
7603 * @scope Roo.EventObject.prototype
7609 /** The normal browser event */
7610 browserEvent : null,
7611 /** The button pressed in a mouse event */
7613 /** True if the shift key was down during the event */
7615 /** True if the control key was down during the event */
7617 /** True if the alt key was down during the event */
7676 setEvent : function(e){
7677 if(e == this || (e && e.browserEvent)){ // already wrapped
7680 this.browserEvent = e;
7682 // normalize buttons
7683 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
7684 if(e.type == 'click' && this.button == -1){
7688 this.shiftKey = e.shiftKey;
7689 // mac metaKey behaves like ctrlKey
7690 this.ctrlKey = e.ctrlKey || e.metaKey;
7691 this.altKey = e.altKey;
7692 // in getKey these will be normalized for the mac
7693 this.keyCode = e.keyCode;
7694 // keyup warnings on firefox.
7695 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
7696 // cache the target for the delayed and or buffered events
7697 this.target = E.getTarget(e);
7699 this.xy = E.getXY(e);
7702 this.shiftKey = false;
7703 this.ctrlKey = false;
7704 this.altKey = false;
7714 * Stop the event (preventDefault and stopPropagation)
7716 stopEvent : function(){
7717 if(this.browserEvent){
7718 if(this.browserEvent.type == 'mousedown'){
7719 Roo.EventManager.stoppedMouseDownEvent.fire(this);
7721 E.stopEvent(this.browserEvent);
7726 * Prevents the browsers default handling of the event.
7728 preventDefault : function(){
7729 if(this.browserEvent){
7730 E.preventDefault(this.browserEvent);
7735 isNavKeyPress : function(){
7736 var k = this.keyCode;
7737 k = Roo.isSafari ? (safariKeys[k] || k) : k;
7738 return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
7741 isSpecialKey : function(){
7742 var k = this.keyCode;
7743 return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13 || k == 40 || k == 27 ||
7744 (k == 16) || (k == 17) ||
7745 (k >= 18 && k <= 20) ||
7746 (k >= 33 && k <= 35) ||
7747 (k >= 36 && k <= 39) ||
7748 (k >= 44 && k <= 45);
7751 * Cancels bubbling of the event.
7753 stopPropagation : function(){
7754 if(this.browserEvent){
7755 if(this.type == 'mousedown'){
7756 Roo.EventManager.stoppedMouseDownEvent.fire(this);
7758 E.stopPropagation(this.browserEvent);
7763 * Gets the key code for the event.
7766 getCharCode : function(){
7767 return this.charCode || this.keyCode;
7771 * Returns a normalized keyCode for the event.
7772 * @return {Number} The key code
7774 getKey : function(){
7775 var k = this.keyCode || this.charCode;
7776 return Roo.isSafari ? (safariKeys[k] || k) : k;
7780 * Gets the x coordinate of the event.
7783 getPageX : function(){
7788 * Gets the y coordinate of the event.
7791 getPageY : function(){
7796 * Gets the time of the event.
7799 getTime : function(){
7800 if(this.browserEvent){
7801 return E.getTime(this.browserEvent);
7807 * Gets the page coordinates of the event.
7808 * @return {Array} The xy values like [x, y]
7815 * Gets the target for the event.
7816 * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
7817 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7818 search as a number or element (defaults to 10 || document.body)
7819 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7820 * @return {HTMLelement}
7822 getTarget : function(selector, maxDepth, returnEl){
7823 return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
7826 * Gets the related target.
7827 * @return {HTMLElement}
7829 getRelatedTarget : function(){
7830 if(this.browserEvent){
7831 return E.getRelatedTarget(this.browserEvent);
7837 * Normalizes mouse wheel delta across browsers
7838 * @return {Number} The delta
7840 getWheelDelta : function(){
7841 var e = this.browserEvent;
7843 if(e.wheelDelta){ /* IE/Opera. */
7844 delta = e.wheelDelta/120;
7845 }else if(e.detail){ /* Mozilla case. */
7846 delta = -e.detail/3;
7852 * Returns true if the control, meta, shift or alt key was pressed during this event.
7855 hasModifier : function(){
7856 return !!((this.ctrlKey || this.altKey) || this.shiftKey);
7860 * Returns true if the target of this event equals el or is a child of el
7861 * @param {String/HTMLElement/Element} el
7862 * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
7865 within : function(el, related){
7866 var t = this[related ? "getRelatedTarget" : "getTarget"]();
7867 return t && Roo.fly(el).contains(t);
7870 getPoint : function(){
7871 return new Roo.lib.Point(this.xy[0], this.xy[1]);
7875 return new Roo.EventObjectImpl();
7880 * Ext JS Library 1.1.1
7881 * Copyright(c) 2006-2007, Ext JS, LLC.
7883 * Originally Released Under LGPL - original licence link has changed is not relivant.
7886 * <script type="text/javascript">
7890 // was in Composite Element!??!?!
7893 var D = Roo.lib.Dom;
7894 var E = Roo.lib.Event;
7895 var A = Roo.lib.Anim;
7897 // local style camelizing for speed
7899 var camelRe = /(-[a-z])/gi;
7900 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
7901 var view = document.defaultView;
7904 * @class Roo.Element
7905 * Represents an Element in the DOM.<br><br>
7908 var el = Roo.get("my-div");
7911 var el = getEl("my-div");
7913 // or with a DOM element
7914 var el = Roo.get(myDivElement);
7916 * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
7917 * each call instead of constructing a new one.<br><br>
7918 * <b>Animations</b><br />
7919 * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
7920 * should either be a boolean (true) or an object literal with animation options. The animation options are:
7922 Option Default Description
7923 --------- -------- ---------------------------------------------
7924 duration .35 The duration of the animation in seconds
7925 easing easeOut The YUI easing method
7926 callback none A function to execute when the anim completes
7927 scope this The scope (this) of the callback function
7929 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
7930 * manipulate the animation. Here's an example:
7932 var el = Roo.get("my-div");
7937 // default animation
7938 el.setWidth(100, true);
7940 // animation with some options set
7947 // using the "anim" property to get the Anim object
7953 el.setWidth(100, opt);
7955 if(opt.anim.isAnimated()){
7959 * <b> Composite (Collections of) Elements</b><br />
7960 * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
7961 * @constructor Create a new Element directly.
7962 * @param {String/HTMLElement} element
7963 * @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).
7965 Roo.Element = function(element, forceNew)
7967 var dom = typeof element == "string" ?
7968 document.getElementById(element) : element;
7970 this.listeners = {};
7972 if(!dom){ // invalid id/element
7976 if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
7977 return Roo.Element.cache[id];
7987 * The DOM element ID
7990 this.id = id || Roo.id(dom);
7992 return this; // assumed for cctor?
7995 var El = Roo.Element;
7999 * The element's default display mode (defaults to "")
8002 originalDisplay : "",
8005 // note this is overridden in BS version..
8008 * The default unit to append to CSS values where a unit isn't provided (defaults to px).
8014 * Sets the element's visibility mode. When setVisible() is called it
8015 * will use this to determine whether to set the visibility or the display property.
8016 * @param visMode Element.VISIBILITY or Element.DISPLAY
8017 * @return {Roo.Element} this
8019 setVisibilityMode : function(visMode){
8020 this.visibilityMode = visMode;
8024 * Convenience method for setVisibilityMode(Element.DISPLAY)
8025 * @param {String} display (optional) What to set display to when visible
8026 * @return {Roo.Element} this
8028 enableDisplayMode : function(display){
8029 this.setVisibilityMode(El.DISPLAY);
8030 if(typeof display != "undefined") { this.originalDisplay = display; }
8035 * 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)
8036 * @param {String} selector The simple selector to test
8037 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
8038 search as a number or element (defaults to 10 || document.body)
8039 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
8040 * @return {HTMLElement} The matching DOM node (or null if no match was found)
8042 findParent : function(simpleSelector, maxDepth, returnEl){
8043 var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
8044 maxDepth = maxDepth || 50;
8045 if(typeof maxDepth != "number"){
8046 stopEl = Roo.getDom(maxDepth);
8049 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
8050 if(dq.is(p, simpleSelector)){
8051 return returnEl ? Roo.get(p) : p;
8061 * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
8062 * @param {String} selector The simple selector to test
8063 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
8064 search as a number or element (defaults to 10 || document.body)
8065 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
8066 * @return {HTMLElement} The matching DOM node (or null if no match was found)
8068 findParentNode : function(simpleSelector, maxDepth, returnEl){
8069 var p = Roo.fly(this.dom.parentNode, '_internal');
8070 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
8074 * Looks at the scrollable parent element
8076 findScrollableParent : function()
8078 var overflowRegex = /(auto|scroll)/;
8080 if(this.getStyle('position') === 'fixed'){
8081 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
8084 var excludeStaticParent = this.getStyle('position') === "absolute";
8086 for (var parent = this; (parent = Roo.get(parent.dom.parentNode));){
8088 if (excludeStaticParent && parent.getStyle('position') === "static") {
8092 if (overflowRegex.test(parent.getStyle('overflow') + parent.getStyle('overflow-x') + parent.getStyle('overflow-y'))){
8096 if(parent.dom.nodeName.toLowerCase() == 'body'){
8097 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
8101 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
8105 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
8106 * This is a shortcut for findParentNode() that always returns an Roo.Element.
8107 * @param {String} selector The simple selector to test
8108 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
8109 search as a number or element (defaults to 10 || document.body)
8110 * @return {Roo.Element} The matching DOM node (or null if no match was found)
8112 up : function(simpleSelector, maxDepth){
8113 return this.findParentNode(simpleSelector, maxDepth, true);
8119 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
8120 * @param {String} selector The simple selector to test
8121 * @return {Boolean} True if this element matches the selector, else false
8123 is : function(simpleSelector){
8124 return Roo.DomQuery.is(this.dom, simpleSelector);
8128 * Perform animation on this element.
8129 * @param {Object} args The YUI animation control args
8130 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
8131 * @param {Function} onComplete (optional) Function to call when animation completes
8132 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
8133 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
8134 * @return {Roo.Element} this
8136 animate : function(args, duration, onComplete, easing, animType){
8137 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
8142 * @private Internal animation call
8144 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
8145 animType = animType || 'run';
8147 var anim = Roo.lib.Anim[animType](
8149 (opt.duration || defaultDur) || .35,
8150 (opt.easing || defaultEase) || 'easeOut',
8152 Roo.callback(cb, this);
8153 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
8161 // private legacy anim prep
8162 preanim : function(a, i){
8163 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
8167 * Removes worthless text nodes
8168 * @param {Boolean} forceReclean (optional) By default the element
8169 * keeps track if it has been cleaned already so
8170 * you can call this over and over. However, if you update the element and
8171 * need to force a reclean, you can pass true.
8173 clean : function(forceReclean){
8174 if(this.isCleaned && forceReclean !== true){
8178 var d = this.dom, n = d.firstChild, ni = -1;
8180 var nx = n.nextSibling;
8181 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
8188 this.isCleaned = true;
8193 calcOffsetsTo : function(el){
8196 var restorePos = false;
8197 if(el.getStyle('position') == 'static'){
8198 el.position('relative');
8203 while(op && op != d && op.tagName != 'HTML'){
8206 op = op.offsetParent;
8209 el.position('static');
8215 * Scrolls this element into view within the passed container.
8216 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
8217 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
8218 * @return {Roo.Element} this
8220 scrollIntoView : function(container, hscroll){
8221 var c = Roo.getDom(container) || document.body;
8224 var o = this.calcOffsetsTo(c),
8227 b = t+el.offsetHeight,
8228 r = l+el.offsetWidth;
8230 var ch = c.clientHeight;
8231 var ct = parseInt(c.scrollTop, 10);
8232 var cl = parseInt(c.scrollLeft, 10);
8234 var cr = cl + c.clientWidth;
8242 if(hscroll !== false){
8246 c.scrollLeft = r-c.clientWidth;
8253 scrollChildIntoView : function(child, hscroll){
8254 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
8258 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
8259 * the new height may not be available immediately.
8260 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
8261 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
8262 * @param {Function} onComplete (optional) Function to call when animation completes
8263 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
8264 * @return {Roo.Element} this
8266 autoHeight : function(animate, duration, onComplete, easing){
8267 var oldHeight = this.getHeight();
8269 this.setHeight(1); // force clipping
8270 setTimeout(function(){
8271 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
8273 this.setHeight(height);
8275 if(typeof onComplete == "function"){
8279 this.setHeight(oldHeight); // restore original height
8280 this.setHeight(height, animate, duration, function(){
8282 if(typeof onComplete == "function") { onComplete(); }
8283 }.createDelegate(this), easing);
8285 }.createDelegate(this), 0);
8290 * Returns true if this element is an ancestor of the passed element
8291 * @param {HTMLElement/String} el The element to check
8292 * @return {Boolean} True if this element is an ancestor of el, else false
8294 contains : function(el){
8295 if(!el){return false;}
8296 return D.isAncestor(this.dom, el.dom ? el.dom : el);
8300 * Checks whether the element is currently visible using both visibility and display properties.
8301 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
8302 * @return {Boolean} True if the element is currently visible, else false
8304 isVisible : function(deep) {
8305 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
8306 if(deep !== true || !vis){
8309 var p = this.dom.parentNode;
8310 while(p && p.tagName.toLowerCase() != "body"){
8311 if(!Roo.fly(p, '_isVisible').isVisible()){
8320 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
8321 * @param {String} selector The CSS selector
8322 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
8323 * @return {CompositeElement/CompositeElementLite} The composite element
8325 select : function(selector, unique){
8326 return El.select(selector, unique, this.dom);
8330 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
8331 * @param {String} selector The CSS selector
8332 * @return {Array} An array of the matched nodes
8334 query : function(selector, unique){
8335 return Roo.DomQuery.select(selector, this.dom);
8339 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
8340 * @param {String} selector The CSS selector
8341 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
8342 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
8344 child : function(selector, returnDom){
8345 var n = Roo.DomQuery.selectNode(selector, this.dom);
8346 return returnDom ? n : Roo.get(n);
8350 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
8351 * @param {String} selector The CSS selector
8352 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
8353 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
8355 down : function(selector, returnDom){
8356 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
8357 return returnDom ? n : Roo.get(n);
8361 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
8362 * @param {String} group The group the DD object is member of
8363 * @param {Object} config The DD config object
8364 * @param {Object} overrides An object containing methods to override/implement on the DD object
8365 * @return {Roo.dd.DD} The DD object
8367 initDD : function(group, config, overrides){
8368 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
8369 return Roo.apply(dd, overrides);
8373 * Initializes a {@link Roo.dd.DDProxy} object for this element.
8374 * @param {String} group The group the DDProxy object is member of
8375 * @param {Object} config The DDProxy config object
8376 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
8377 * @return {Roo.dd.DDProxy} The DDProxy object
8379 initDDProxy : function(group, config, overrides){
8380 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
8381 return Roo.apply(dd, overrides);
8385 * Initializes a {@link Roo.dd.DDTarget} object for this element.
8386 * @param {String} group The group the DDTarget object is member of
8387 * @param {Object} config The DDTarget config object
8388 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
8389 * @return {Roo.dd.DDTarget} The DDTarget object
8391 initDDTarget : function(group, config, overrides){
8392 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
8393 return Roo.apply(dd, overrides);
8397 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
8398 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
8399 * @param {Boolean} visible Whether the element is visible
8400 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8401 * @return {Roo.Element} this
8403 setVisible : function(visible, animate){
8405 if(this.visibilityMode == El.DISPLAY){
8406 this.setDisplayed(visible);
8409 this.dom.style.visibility = visible ? "visible" : "hidden";
8412 // closure for composites
8414 var visMode = this.visibilityMode;
8416 this.setOpacity(.01);
8417 this.setVisible(true);
8419 this.anim({opacity: { to: (visible?1:0) }},
8420 this.preanim(arguments, 1),
8421 null, .35, 'easeIn', function(){
8423 if(visMode == El.DISPLAY){
8424 dom.style.display = "none";
8426 dom.style.visibility = "hidden";
8428 Roo.get(dom).setOpacity(1);
8436 * Returns true if display is not "none"
8439 isDisplayed : function() {
8440 return this.getStyle("display") != "none";
8444 * Toggles the element's visibility or display, depending on visibility mode.
8445 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8446 * @return {Roo.Element} this
8448 toggle : function(animate){
8449 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
8454 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
8455 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
8456 * @return {Roo.Element} this
8458 setDisplayed : function(value) {
8459 if(typeof value == "boolean"){
8460 value = value ? this.originalDisplay : "none";
8462 this.setStyle("display", value);
8467 * Tries to focus the element. Any exceptions are caught and ignored.
8468 * @return {Roo.Element} this
8470 focus : function() {
8478 * Tries to blur the element. Any exceptions are caught and ignored.
8479 * @return {Roo.Element} this
8489 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
8490 * @param {String/Array} className The CSS class to add, or an array of classes
8491 * @return {Roo.Element} this
8493 addClass : function(className){
8494 if(className instanceof Array){
8495 for(var i = 0, len = className.length; i < len; i++) {
8496 this.addClass(className[i]);
8499 if(className && !this.hasClass(className)){
8500 if (this.dom instanceof SVGElement) {
8501 this.dom.className.baseVal =this.dom.className.baseVal + " " + className;
8503 this.dom.className = this.dom.className + " " + className;
8511 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
8512 * @param {String/Array} className The CSS class to add, or an array of classes
8513 * @return {Roo.Element} this
8515 radioClass : function(className){
8516 var siblings = this.dom.parentNode.childNodes;
8517 for(var i = 0; i < siblings.length; i++) {
8518 var s = siblings[i];
8519 if(s.nodeType == 1){
8520 Roo.get(s).removeClass(className);
8523 this.addClass(className);
8528 * Removes one or more CSS classes from the element.
8529 * @param {String/Array} className The CSS class to remove, or an array of classes
8530 * @return {Roo.Element} this
8532 removeClass : function(className){
8534 var cn = this.dom instanceof SVGElement ? this.dom.className.baseVal : this.dom.className;
8535 if(!className || !cn){
8538 if(className instanceof Array){
8539 for(var i = 0, len = className.length; i < len; i++) {
8540 this.removeClass(className[i]);
8543 if(this.hasClass(className)){
8544 var re = this.classReCache[className];
8546 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
8547 this.classReCache[className] = re;
8549 if (this.dom instanceof SVGElement) {
8550 this.dom.className.baseVal = cn.replace(re, " ");
8552 this.dom.className = cn.replace(re, " ");
8563 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
8564 * @param {String} className The CSS class to toggle
8565 * @return {Roo.Element} this
8567 toggleClass : function(className){
8568 if(this.hasClass(className)){
8569 this.removeClass(className);
8571 this.addClass(className);
8577 * Checks if the specified CSS class exists on this element's DOM node.
8578 * @param {String} className The CSS class to check for
8579 * @return {Boolean} True if the class exists, else false
8581 hasClass : function(className){
8582 if (this.dom instanceof SVGElement) {
8583 return className && (' '+this.dom.className.baseVal +' ').indexOf(' '+className+' ') != -1;
8585 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
8589 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
8590 * @param {String} oldClassName The CSS class to replace
8591 * @param {String} newClassName The replacement CSS class
8592 * @return {Roo.Element} this
8594 replaceClass : function(oldClassName, newClassName){
8595 this.removeClass(oldClassName);
8596 this.addClass(newClassName);
8601 * Returns an object with properties matching the styles requested.
8602 * For example, el.getStyles('color', 'font-size', 'width') might return
8603 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
8604 * @param {String} style1 A style name
8605 * @param {String} style2 A style name
8606 * @param {String} etc.
8607 * @return {Object} The style object
8609 getStyles : function(){
8610 var a = arguments, len = a.length, r = {};
8611 for(var i = 0; i < len; i++){
8612 r[a[i]] = this.getStyle(a[i]);
8618 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
8619 * @param {String} property The style property whose value is returned.
8620 * @return {String} The current value of the style property for this element.
8622 getStyle : function(){
8623 return view && view.getComputedStyle ?
8625 var el = this.dom, v, cs, camel;
8626 if(prop == 'float'){
8629 if(el.style && (v = el.style[prop])){
8632 if(cs = view.getComputedStyle(el, "")){
8633 if(!(camel = propCache[prop])){
8634 camel = propCache[prop] = prop.replace(camelRe, camelFn);
8641 var el = this.dom, v, cs, camel;
8642 if(prop == 'opacity'){
8643 if(typeof el.style.filter == 'string'){
8644 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
8646 var fv = parseFloat(m[1]);
8648 return fv ? fv / 100 : 0;
8653 }else if(prop == 'float'){
8654 prop = "styleFloat";
8656 if(!(camel = propCache[prop])){
8657 camel = propCache[prop] = prop.replace(camelRe, camelFn);
8659 if(v = el.style[camel]){
8662 if(cs = el.currentStyle){
8670 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
8671 * @param {String/Object} property The style property to be set, or an object of multiple styles.
8672 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
8673 * @return {Roo.Element} this
8675 setStyle : function(prop, value){
8676 if(typeof prop == "string"){
8678 if (prop == 'float') {
8679 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
8684 if(!(camel = propCache[prop])){
8685 camel = propCache[prop] = prop.replace(camelRe, camelFn);
8688 if(camel == 'opacity') {
8689 this.setOpacity(value);
8691 this.dom.style[camel] = value;
8694 for(var style in prop){
8695 if(typeof prop[style] != "function"){
8696 this.setStyle(style, prop[style]);
8704 * More flexible version of {@link #setStyle} for setting style properties.
8705 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
8706 * a function which returns such a specification.
8707 * @return {Roo.Element} this
8709 applyStyles : function(style){
8710 Roo.DomHelper.applyStyles(this.dom, style);
8715 * 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).
8716 * @return {Number} The X position of the element
8719 return D.getX(this.dom);
8723 * 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).
8724 * @return {Number} The Y position of the element
8727 return D.getY(this.dom);
8731 * 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).
8732 * @return {Array} The XY position of the element
8735 return D.getXY(this.dom);
8739 * 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).
8740 * @param {Number} The X position of the element
8741 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8742 * @return {Roo.Element} this
8744 setX : function(x, animate){
8746 D.setX(this.dom, x);
8748 this.setXY([x, this.getY()], this.preanim(arguments, 1));
8754 * 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).
8755 * @param {Number} The Y position of the element
8756 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8757 * @return {Roo.Element} this
8759 setY : function(y, animate){
8761 D.setY(this.dom, y);
8763 this.setXY([this.getX(), y], this.preanim(arguments, 1));
8769 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
8770 * @param {String} left The left CSS property value
8771 * @return {Roo.Element} this
8773 setLeft : function(left){
8774 this.setStyle("left", this.addUnits(left));
8779 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
8780 * @param {String} top The top CSS property value
8781 * @return {Roo.Element} this
8783 setTop : function(top){
8784 this.setStyle("top", this.addUnits(top));
8789 * Sets the element's CSS right style.
8790 * @param {String} right The right CSS property value
8791 * @return {Roo.Element} this
8793 setRight : function(right){
8794 this.setStyle("right", this.addUnits(right));
8799 * Sets the element's CSS bottom style.
8800 * @param {String} bottom The bottom CSS property value
8801 * @return {Roo.Element} this
8803 setBottom : function(bottom){
8804 this.setStyle("bottom", this.addUnits(bottom));
8809 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
8810 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
8811 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
8812 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8813 * @return {Roo.Element} this
8815 setXY : function(pos, animate){
8817 D.setXY(this.dom, pos);
8819 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
8825 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
8826 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
8827 * @param {Number} x X value for new position (coordinates are page-based)
8828 * @param {Number} y Y value for new position (coordinates are page-based)
8829 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8830 * @return {Roo.Element} this
8832 setLocation : function(x, y, animate){
8833 this.setXY([x, y], this.preanim(arguments, 2));
8838 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
8839 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
8840 * @param {Number} x X value for new position (coordinates are page-based)
8841 * @param {Number} y Y value for new position (coordinates are page-based)
8842 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8843 * @return {Roo.Element} this
8845 moveTo : function(x, y, animate){
8846 this.setXY([x, y], this.preanim(arguments, 2));
8851 * Returns the region of the given element.
8852 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
8853 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
8855 getRegion : function(){
8856 return D.getRegion(this.dom);
8860 * Returns the offset height of the element
8861 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
8862 * @return {Number} The element's height
8864 getHeight : function(contentHeight){
8865 var h = this.dom.offsetHeight || 0;
8866 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
8870 * Returns the offset width of the element
8871 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
8872 * @return {Number} The element's width
8874 getWidth : function(contentWidth){
8875 var w = this.dom.offsetWidth || 0;
8876 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
8880 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
8881 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
8882 * if a height has not been set using CSS.
8885 getComputedHeight : function(){
8886 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
8888 h = parseInt(this.getStyle('height'), 10) || 0;
8889 if(!this.isBorderBox()){
8890 h += this.getFrameWidth('tb');
8897 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
8898 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
8899 * if a width has not been set using CSS.
8902 getComputedWidth : function(){
8903 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
8905 w = parseInt(this.getStyle('width'), 10) || 0;
8906 if(!this.isBorderBox()){
8907 w += this.getFrameWidth('lr');
8914 * Returns the size of the element.
8915 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
8916 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
8918 getSize : function(contentSize){
8919 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
8923 * Returns the width and height of the viewport.
8924 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
8926 getViewSize : function(){
8927 var d = this.dom, doc = document, aw = 0, ah = 0;
8928 if(d == doc || d == doc.body){
8929 return {width : D.getViewWidth(), height: D.getViewHeight()};
8932 width : d.clientWidth,
8933 height: d.clientHeight
8939 * Returns the value of the "value" attribute
8940 * @param {Boolean} asNumber true to parse the value as a number
8941 * @return {String/Number}
8943 getValue : function(asNumber){
8944 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
8948 adjustWidth : function(width){
8949 if(typeof width == "number"){
8950 if(this.autoBoxAdjust && !this.isBorderBox()){
8951 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8961 adjustHeight : function(height){
8962 if(typeof height == "number"){
8963 if(this.autoBoxAdjust && !this.isBorderBox()){
8964 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8974 * Set the width of the element
8975 * @param {Number} width The new width
8976 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8977 * @return {Roo.Element} this
8979 setWidth : function(width, animate){
8980 width = this.adjustWidth(width);
8982 this.dom.style.width = this.addUnits(width);
8984 this.anim({width: {to: width}}, this.preanim(arguments, 1));
8990 * Set the height of the element
8991 * @param {Number} height The new height
8992 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8993 * @return {Roo.Element} this
8995 setHeight : function(height, animate){
8996 height = this.adjustHeight(height);
8998 this.dom.style.height = this.addUnits(height);
9000 this.anim({height: {to: height}}, this.preanim(arguments, 1));
9006 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
9007 * @param {Number} width The new width
9008 * @param {Number} height The new height
9009 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9010 * @return {Roo.Element} this
9012 setSize : function(width, height, animate){
9013 if(typeof width == "object"){ // in case of object from getSize()
9014 height = width.height; width = width.width;
9016 width = this.adjustWidth(width); height = this.adjustHeight(height);
9018 this.dom.style.width = this.addUnits(width);
9019 this.dom.style.height = this.addUnits(height);
9021 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
9027 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
9028 * @param {Number} x X value for new position (coordinates are page-based)
9029 * @param {Number} y Y value for new position (coordinates are page-based)
9030 * @param {Number} width The new width
9031 * @param {Number} height The new height
9032 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9033 * @return {Roo.Element} this
9035 setBounds : function(x, y, width, height, animate){
9037 this.setSize(width, height);
9038 this.setLocation(x, y);
9040 width = this.adjustWidth(width); height = this.adjustHeight(height);
9041 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
9042 this.preanim(arguments, 4), 'motion');
9048 * 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.
9049 * @param {Roo.lib.Region} region The region to fill
9050 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9051 * @return {Roo.Element} this
9053 setRegion : function(region, animate){
9054 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
9059 * Appends an event handler
9061 * @param {String} eventName The type of event to append
9062 * @param {Function} fn The method the event invokes
9063 * @param {Object} scope (optional) The scope (this object) of the fn
9064 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9066 addListener : function(eventName, fn, scope, options)
9068 if (eventName == 'dblclick') { // doublclick (touchstart) - faked on touch.
9069 this.addListener('touchstart', this.onTapHandler, this);
9072 // we need to handle a special case where dom element is a svg element.
9073 // in this case we do not actua
9078 if (this.dom instanceof SVGElement && !(this.dom instanceof SVGSVGElement)) {
9079 if (typeof(this.listeners[eventName]) == 'undefined') {
9080 this.listeners[eventName] = new Roo.util.Event(this, eventName);
9082 this.listeners[eventName].addListener(fn, scope, options);
9087 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
9092 onTapHandler : function(event)
9094 if(!this.tapedTwice) {
9095 this.tapedTwice = true;
9097 setTimeout( function() {
9098 s.tapedTwice = false;
9102 event.preventDefault();
9103 var revent = new MouseEvent('dblclick', {
9109 this.dom.dispatchEvent(revent);
9110 //action on double tap goes below
9115 * Removes an event handler from this element
9116 * @param {String} eventName the type of event to remove
9117 * @param {Function} fn the method the event invokes
9118 * @param {Function} scope (needed for svg fake listeners)
9119 * @return {Roo.Element} this
9121 removeListener : function(eventName, fn, scope){
9122 Roo.EventManager.removeListener(this.dom, eventName, fn);
9123 if (typeof(this.listeners) == 'undefined' || typeof(this.listeners[eventName]) == 'undefined') {
9126 this.listeners[eventName].removeListener(fn, scope);
9131 * Removes all previous added listeners from this element
9132 * @return {Roo.Element} this
9134 removeAllListeners : function(){
9135 E.purgeElement(this.dom);
9136 this.listeners = {};
9140 relayEvent : function(eventName, observable){
9141 this.on(eventName, function(e){
9142 observable.fireEvent(eventName, e);
9148 * Set the opacity of the element
9149 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
9150 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9151 * @return {Roo.Element} this
9153 setOpacity : function(opacity, animate){
9155 var s = this.dom.style;
9158 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
9159 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
9161 s.opacity = opacity;
9164 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
9170 * Gets the left X coordinate
9171 * @param {Boolean} local True to get the local css position instead of page coordinate
9174 getLeft : function(local){
9178 return parseInt(this.getStyle("left"), 10) || 0;
9183 * Gets the right X coordinate of the element (element X position + element width)
9184 * @param {Boolean} local True to get the local css position instead of page coordinate
9187 getRight : function(local){
9189 return this.getX() + this.getWidth();
9191 return (this.getLeft(true) + this.getWidth()) || 0;
9196 * Gets the top Y coordinate
9197 * @param {Boolean} local True to get the local css position instead of page coordinate
9200 getTop : function(local) {
9204 return parseInt(this.getStyle("top"), 10) || 0;
9209 * Gets the bottom Y coordinate of the element (element Y position + element height)
9210 * @param {Boolean} local True to get the local css position instead of page coordinate
9213 getBottom : function(local){
9215 return this.getY() + this.getHeight();
9217 return (this.getTop(true) + this.getHeight()) || 0;
9222 * Initializes positioning on this element. If a desired position is not passed, it will make the
9223 * the element positioned relative IF it is not already positioned.
9224 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
9225 * @param {Number} zIndex (optional) The zIndex to apply
9226 * @param {Number} x (optional) Set the page X position
9227 * @param {Number} y (optional) Set the page Y position
9229 position : function(pos, zIndex, x, y){
9231 if(this.getStyle('position') == 'static'){
9232 this.setStyle('position', 'relative');
9235 this.setStyle("position", pos);
9238 this.setStyle("z-index", zIndex);
9240 if(x !== undefined && y !== undefined){
9242 }else if(x !== undefined){
9244 }else if(y !== undefined){
9250 * Clear positioning back to the default when the document was loaded
9251 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
9252 * @return {Roo.Element} this
9254 clearPositioning : function(value){
9262 "position" : "static"
9268 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
9269 * snapshot before performing an update and then restoring the element.
9272 getPositioning : function(){
9273 var l = this.getStyle("left");
9274 var t = this.getStyle("top");
9276 "position" : this.getStyle("position"),
9278 "right" : l ? "" : this.getStyle("right"),
9280 "bottom" : t ? "" : this.getStyle("bottom"),
9281 "z-index" : this.getStyle("z-index")
9286 * Gets the width of the border(s) for the specified side(s)
9287 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
9288 * passing lr would get the border (l)eft width + the border (r)ight width.
9289 * @return {Number} The width of the sides passed added together
9291 getBorderWidth : function(side){
9292 return this.addStyles(side, El.borders);
9296 * Gets the width of the padding(s) for the specified side(s)
9297 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
9298 * passing lr would get the padding (l)eft + the padding (r)ight.
9299 * @return {Number} The padding of the sides passed added together
9301 getPadding : function(side){
9302 return this.addStyles(side, El.paddings);
9306 * Set positioning with an object returned by getPositioning().
9307 * @param {Object} posCfg
9308 * @return {Roo.Element} this
9310 setPositioning : function(pc){
9311 this.applyStyles(pc);
9312 if(pc.right == "auto"){
9313 this.dom.style.right = "";
9315 if(pc.bottom == "auto"){
9316 this.dom.style.bottom = "";
9322 fixDisplay : function(){
9323 if(this.getStyle("display") == "none"){
9324 this.setStyle("visibility", "hidden");
9325 this.setStyle("display", this.originalDisplay); // first try reverting to default
9326 if(this.getStyle("display") == "none"){ // if that fails, default to block
9327 this.setStyle("display", "block");
9333 * Quick set left and top adding default units
9334 * @param {String} left The left CSS property value
9335 * @param {String} top The top CSS property value
9336 * @return {Roo.Element} this
9338 setLeftTop : function(left, top){
9339 this.dom.style.left = this.addUnits(left);
9340 this.dom.style.top = this.addUnits(top);
9345 * Move this element relative to its current position.
9346 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9347 * @param {Number} distance How far to move the element in pixels
9348 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9349 * @return {Roo.Element} this
9351 move : function(direction, distance, animate){
9352 var xy = this.getXY();
9353 direction = direction.toLowerCase();
9357 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
9361 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
9366 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
9371 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
9378 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
9379 * @return {Roo.Element} this
9382 if(!this.isClipped){
9383 this.isClipped = true;
9384 this.originalClip = {
9385 "o": this.getStyle("overflow"),
9386 "x": this.getStyle("overflow-x"),
9387 "y": this.getStyle("overflow-y")
9389 this.setStyle("overflow", "hidden");
9390 this.setStyle("overflow-x", "hidden");
9391 this.setStyle("overflow-y", "hidden");
9397 * Return clipping (overflow) to original clipping before clip() was called
9398 * @return {Roo.Element} this
9400 unclip : function(){
9402 this.isClipped = false;
9403 var o = this.originalClip;
9404 if(o.o){this.setStyle("overflow", o.o);}
9405 if(o.x){this.setStyle("overflow-x", o.x);}
9406 if(o.y){this.setStyle("overflow-y", o.y);}
9413 * Gets the x,y coordinates specified by the anchor position on the element.
9414 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
9415 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
9416 * {width: (target width), height: (target height)} (defaults to the element's current size)
9417 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
9418 * @return {Array} [x, y] An array containing the element's x and y coordinates
9420 getAnchorXY : function(anchor, local, s){
9421 //Passing a different size is useful for pre-calculating anchors,
9422 //especially for anchored animations that change the el size.
9424 var w, h, vp = false;
9427 if(d == document.body || d == document){
9429 w = D.getViewWidth(); h = D.getViewHeight();
9431 w = this.getWidth(); h = this.getHeight();
9434 w = s.width; h = s.height;
9436 var x = 0, y = 0, r = Math.round;
9437 switch((anchor || "tl").toLowerCase()){
9479 var sc = this.getScroll();
9480 return [x + sc.left, y + sc.top];
9482 //Add the element's offset xy
9483 var o = this.getXY();
9484 return [x+o[0], y+o[1]];
9488 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
9489 * supported position values.
9490 * @param {String/HTMLElement/Roo.Element} element The element to align to.
9491 * @param {String} position The position to align to.
9492 * @param {Array} offsets (optional) Offset the positioning by [x, y]
9493 * @return {Array} [x, y]
9495 getAlignToXY : function(el, p, o)
9500 throw "Element.alignTo with an element that doesn't exist";
9502 var c = false; //constrain to viewport
9503 var p1 = "", p2 = "";
9510 }else if(p.indexOf("-") == -1){
9513 p = p.toLowerCase();
9514 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
9516 throw "Element.alignTo with an invalid alignment " + p;
9518 p1 = m[1]; p2 = m[2]; c = !!m[3];
9520 //Subtract the aligned el's internal xy from the target's offset xy
9521 //plus custom offset to get the aligned el's new offset xy
9522 var a1 = this.getAnchorXY(p1, true);
9523 var a2 = el.getAnchorXY(p2, false);
9524 var x = a2[0] - a1[0] + o[0];
9525 var y = a2[1] - a1[1] + o[1];
9527 //constrain the aligned el to viewport if necessary
9528 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
9529 // 5px of margin for ie
9530 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
9532 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
9533 //perpendicular to the vp border, allow the aligned el to slide on that border,
9534 //otherwise swap the aligned el to the opposite border of the target.
9535 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
9536 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
9537 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t") );
9538 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
9541 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
9542 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
9544 if((x+w) > dw + scrollX){
9545 x = swapX ? r.left-w : dw+scrollX-w;
9548 x = swapX ? r.right : scrollX;
9550 if((y+h) > dh + scrollY){
9551 y = swapY ? r.top-h : dh+scrollY-h;
9554 y = swapY ? r.bottom : scrollY;
9561 getConstrainToXY : function(){
9562 var os = {top:0, left:0, bottom:0, right: 0};
9564 return function(el, local, offsets, proposedXY){
9566 offsets = offsets ? Roo.applyIf(offsets, os) : os;
9568 var vw, vh, vx = 0, vy = 0;
9569 if(el.dom == document.body || el.dom == document){
9570 vw = Roo.lib.Dom.getViewWidth();
9571 vh = Roo.lib.Dom.getViewHeight();
9573 vw = el.dom.clientWidth;
9574 vh = el.dom.clientHeight;
9576 var vxy = el.getXY();
9582 var s = el.getScroll();
9584 vx += offsets.left + s.left;
9585 vy += offsets.top + s.top;
9587 vw -= offsets.right;
9588 vh -= offsets.bottom;
9593 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
9594 var x = xy[0], y = xy[1];
9595 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
9597 // only move it if it needs it
9600 // first validate right/bottom
9609 // then make sure top/left isn't negative
9618 return moved ? [x, y] : false;
9623 adjustForConstraints : function(xy, parent, offsets){
9624 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
9628 * Aligns this element with another element relative to the specified anchor points. If the other element is the
9629 * document it aligns it to the viewport.
9630 * The position parameter is optional, and can be specified in any one of the following formats:
9632 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
9633 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
9634 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
9635 * deprecated in favor of the newer two anchor syntax below</i>.</li>
9636 * <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
9637 * element's anchor point, and the second value is used as the target's anchor point.</li>
9639 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
9640 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
9641 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
9642 * that specified in order to enforce the viewport constraints.
9643 * Following are all of the supported anchor positions:
9646 ----- -----------------------------
9647 tl The top left corner (default)
9648 t The center of the top edge
9649 tr The top right corner
9650 l The center of the left edge
9651 c In the center of the element
9652 r The center of the right edge
9653 bl The bottom left corner
9654 b The center of the bottom edge
9655 br The bottom right corner
9659 // align el to other-el using the default positioning ("tl-bl", non-constrained)
9660 el.alignTo("other-el");
9662 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
9663 el.alignTo("other-el", "tr?");
9665 // align the bottom right corner of el with the center left edge of other-el
9666 el.alignTo("other-el", "br-l?");
9668 // align the center of el with the bottom left corner of other-el and
9669 // adjust the x position by -6 pixels (and the y position by 0)
9670 el.alignTo("other-el", "c-bl", [-6, 0]);
9672 * @param {String/HTMLElement/Roo.Element} element The element to align to.
9673 * @param {String} position The position to align to.
9674 * @param {Array} offsets (optional) Offset the positioning by [x, y]
9675 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9676 * @return {Roo.Element} this
9678 alignTo : function(element, position, offsets, animate){
9679 var xy = this.getAlignToXY(element, position, offsets);
9680 this.setXY(xy, this.preanim(arguments, 3));
9685 * Anchors an element to another element and realigns it when the window is resized.
9686 * @param {String/HTMLElement/Roo.Element} element The element to align to.
9687 * @param {String} position The position to align to.
9688 * @param {Array} offsets (optional) Offset the positioning by [x, y]
9689 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
9690 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
9691 * is a number, it is used as the buffer delay (defaults to 50ms).
9692 * @param {Function} callback The function to call after the animation finishes
9693 * @return {Roo.Element} this
9695 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
9696 var action = function(){
9697 this.alignTo(el, alignment, offsets, animate);
9698 Roo.callback(callback, this);
9700 Roo.EventManager.onWindowResize(action, this);
9701 var tm = typeof monitorScroll;
9702 if(tm != 'undefined'){
9703 Roo.EventManager.on(window, 'scroll', action, this,
9704 {buffer: tm == 'number' ? monitorScroll : 50});
9706 action.call(this); // align immediately
9710 * Clears any opacity settings from this element. Required in some cases for IE.
9711 * @return {Roo.Element} this
9713 clearOpacity : function(){
9714 if (window.ActiveXObject) {
9715 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
9716 this.dom.style.filter = "";
9719 this.dom.style.opacity = "";
9720 this.dom.style["-moz-opacity"] = "";
9721 this.dom.style["-khtml-opacity"] = "";
9727 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
9728 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9729 * @return {Roo.Element} this
9731 hide : function(animate){
9732 this.setVisible(false, this.preanim(arguments, 0));
9737 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
9738 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9739 * @return {Roo.Element} this
9741 show : function(animate){
9742 this.setVisible(true, this.preanim(arguments, 0));
9747 * @private Test if size has a unit, otherwise appends the default
9749 addUnits : function(size){
9750 return Roo.Element.addUnits(size, this.defaultUnit);
9754 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
9755 * @return {Roo.Element} this
9757 beginMeasure : function(){
9759 if(el.offsetWidth || el.offsetHeight){
9760 return this; // offsets work already
9763 var p = this.dom, b = document.body; // start with this element
9764 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
9765 var pe = Roo.get(p);
9766 if(pe.getStyle('display') == 'none'){
9767 changed.push({el: p, visibility: pe.getStyle("visibility")});
9768 p.style.visibility = "hidden";
9769 p.style.display = "block";
9773 this._measureChanged = changed;
9779 * Restores displays to before beginMeasure was called
9780 * @return {Roo.Element} this
9782 endMeasure : function(){
9783 var changed = this._measureChanged;
9785 for(var i = 0, len = changed.length; i < len; i++) {
9787 r.el.style.visibility = r.visibility;
9788 r.el.style.display = "none";
9790 this._measureChanged = null;
9796 * Update the innerHTML of this element, optionally searching for and processing scripts
9797 * @param {String} html The new HTML
9798 * @param {Boolean} loadScripts (optional) true to look for and process scripts
9799 * @param {Function} callback For async script loading you can be noticed when the update completes
9800 * @return {Roo.Element} this
9802 update : function(html, loadScripts, callback){
9803 if(typeof html == "undefined"){
9806 if(loadScripts !== true){
9807 this.dom.innerHTML = html;
9808 if(typeof callback == "function"){
9816 html += '<span id="' + id + '"></span>';
9818 E.onAvailable(id, function(){
9819 var hd = document.getElementsByTagName("head")[0];
9820 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
9821 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
9822 var typeRe = /\stype=([\'\"])(.*?)\1/i;
9825 while(match = re.exec(html)){
9826 var attrs = match[1];
9827 var srcMatch = attrs ? attrs.match(srcRe) : false;
9828 if(srcMatch && srcMatch[2]){
9829 var s = document.createElement("script");
9830 s.src = srcMatch[2];
9831 var typeMatch = attrs.match(typeRe);
9832 if(typeMatch && typeMatch[2]){
9833 s.type = typeMatch[2];
9836 }else if(match[2] && match[2].length > 0){
9837 if(window.execScript) {
9838 window.execScript(match[2]);
9846 window.eval(match[2]);
9850 var el = document.getElementById(id);
9851 if(el){el.parentNode.removeChild(el);}
9852 if(typeof callback == "function"){
9856 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
9861 * Direct access to the UpdateManager update() method (takes the same parameters).
9862 * @param {String/Function} url The url for this request or a function to call to get the url
9863 * @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}
9864 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
9865 * @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.
9866 * @return {Roo.Element} this
9869 var um = this.getUpdateManager();
9870 um.update.apply(um, arguments);
9875 * Gets this element's UpdateManager
9876 * @return {Roo.UpdateManager} The UpdateManager
9878 getUpdateManager : function(){
9879 if(!this.updateManager){
9880 this.updateManager = new Roo.UpdateManager(this);
9882 return this.updateManager;
9886 * Disables text selection for this element (normalized across browsers)
9887 * @return {Roo.Element} this
9889 unselectable : function(){
9890 this.dom.unselectable = "on";
9891 this.swallowEvent("selectstart", true);
9892 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
9893 this.addClass("x-unselectable");
9898 * Calculates the x, y to center this element on the screen
9899 * @return {Array} The x, y values [x, y]
9901 getCenterXY : function(){
9902 return this.getAlignToXY(document, 'c-c');
9906 * Centers the Element in either the viewport, or another Element.
9907 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
9909 center : function(centerIn){
9910 this.alignTo(centerIn || document, 'c-c');
9915 * Tests various css rules/browsers to determine if this element uses a border box
9918 isBorderBox : function(){
9919 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
9923 * Return a box {x, y, width, height} that can be used to set another elements
9924 * size/location to match this element.
9925 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
9926 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
9927 * @return {Object} box An object in the format {x, y, width, height}
9929 getBox : function(contentBox, local){
9934 var left = parseInt(this.getStyle("left"), 10) || 0;
9935 var top = parseInt(this.getStyle("top"), 10) || 0;
9938 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
9940 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
9942 var l = this.getBorderWidth("l")+this.getPadding("l");
9943 var r = this.getBorderWidth("r")+this.getPadding("r");
9944 var t = this.getBorderWidth("t")+this.getPadding("t");
9945 var b = this.getBorderWidth("b")+this.getPadding("b");
9946 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)};
9948 bx.right = bx.x + bx.width;
9949 bx.bottom = bx.y + bx.height;
9954 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
9955 for more information about the sides.
9956 * @param {String} sides
9959 getFrameWidth : function(sides, onlyContentBox){
9960 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
9964 * 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.
9965 * @param {Object} box The box to fill {x, y, width, height}
9966 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
9967 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9968 * @return {Roo.Element} this
9970 setBox : function(box, adjust, animate){
9971 var w = box.width, h = box.height;
9972 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
9973 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
9974 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
9976 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
9981 * Forces the browser to repaint this element
9982 * @return {Roo.Element} this
9984 repaint : function(){
9986 this.addClass("x-repaint");
9987 setTimeout(function(){
9988 Roo.get(dom).removeClass("x-repaint");
9994 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
9995 * then it returns the calculated width of the sides (see getPadding)
9996 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
9997 * @return {Object/Number}
9999 getMargins : function(side){
10002 top: parseInt(this.getStyle("margin-top"), 10) || 0,
10003 left: parseInt(this.getStyle("margin-left"), 10) || 0,
10004 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
10005 right: parseInt(this.getStyle("margin-right"), 10) || 0
10008 return this.addStyles(side, El.margins);
10013 addStyles : function(sides, styles){
10015 for(var i = 0, len = sides.length; i < len; i++){
10016 v = this.getStyle(styles[sides.charAt(i)]);
10018 w = parseInt(v, 10);
10026 * Creates a proxy element of this element
10027 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
10028 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
10029 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
10030 * @return {Roo.Element} The new proxy element
10032 createProxy : function(config, renderTo, matchBox){
10034 renderTo = Roo.getDom(renderTo);
10036 renderTo = document.body;
10038 config = typeof config == "object" ?
10039 config : {tag : "div", cls: config};
10040 var proxy = Roo.DomHelper.append(renderTo, config, true);
10042 proxy.setBox(this.getBox());
10048 * Puts a mask over this element to disable user interaction. Requires core.css.
10049 * This method can only be applied to elements which accept child nodes.
10050 * @param {String} msg (optional) A message to display in the mask
10051 * @param {String} msgCls (optional) A css class to apply to the msg element - use no-spinner to hide the spinner on bootstrap
10052 * @return {Element} The mask element
10054 mask : function(msg, msgCls)
10056 if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
10057 this.setStyle("position", "relative");
10060 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
10063 this.addClass("x-masked");
10064 this._mask.setDisplayed(true);
10068 var dom = this.dom;
10069 while (dom && dom.style) {
10070 if (!isNaN(parseInt(dom.style.zIndex))) {
10071 z = Math.max(z, parseInt(dom.style.zIndex));
10073 dom = dom.parentNode;
10075 // if we are masking the body - then it hides everything..
10076 if (this.dom == document.body) {
10078 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
10079 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
10082 if(typeof msg == 'string'){
10083 if(!this._maskMsg){
10084 this._maskMsg = Roo.DomHelper.append(this.dom, {
10085 cls: "roo-el-mask-msg",
10089 cls: 'fa fa-spinner fa-spin'
10097 var mm = this._maskMsg;
10098 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
10099 if (mm.dom.lastChild) { // weird IE issue?
10100 mm.dom.lastChild.innerHTML = msg;
10102 mm.setDisplayed(true);
10104 mm.setStyle('z-index', z + 102);
10106 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
10107 this._mask.setHeight(this.getHeight());
10109 this._mask.setStyle('z-index', z + 100);
10115 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
10116 * it is cached for reuse.
10118 unmask : function(removeEl){
10120 if(removeEl === true){
10121 this._mask.remove();
10124 this._maskMsg.remove();
10125 delete this._maskMsg;
10128 this._mask.setDisplayed(false);
10130 this._maskMsg.setDisplayed(false);
10134 this.removeClass("x-masked");
10138 * Returns true if this element is masked
10139 * @return {Boolean}
10141 isMasked : function(){
10142 return this._mask && this._mask.isVisible();
10146 * Creates an iframe shim for this element to keep selects and other windowed objects from
10148 * @return {Roo.Element} The new shim element
10150 createShim : function(){
10151 var el = document.createElement('iframe');
10152 el.frameBorder = 'no';
10153 el.className = 'roo-shim';
10154 if(Roo.isIE && Roo.isSecure){
10155 el.src = Roo.SSL_SECURE_URL;
10157 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
10158 shim.autoBoxAdjust = false;
10163 * Removes this element from the DOM and deletes it from the cache
10165 remove : function(){
10166 if(this.dom.parentNode){
10167 this.dom.parentNode.removeChild(this.dom);
10169 delete El.cache[this.dom.id];
10173 * Sets up event handlers to add and remove a css class when the mouse is over this element
10174 * @param {String} className
10175 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
10176 * mouseout events for children elements
10177 * @return {Roo.Element} this
10179 addClassOnOver : function(className, preventFlicker){
10180 this.on("mouseover", function(){
10181 Roo.fly(this, '_internal').addClass(className);
10183 var removeFn = function(e){
10184 if(preventFlicker !== true || !e.within(this, true)){
10185 Roo.fly(this, '_internal').removeClass(className);
10188 this.on("mouseout", removeFn, this.dom);
10193 * Sets up event handlers to add and remove a css class when this element has the focus
10194 * @param {String} className
10195 * @return {Roo.Element} this
10197 addClassOnFocus : function(className){
10198 this.on("focus", function(){
10199 Roo.fly(this, '_internal').addClass(className);
10201 this.on("blur", function(){
10202 Roo.fly(this, '_internal').removeClass(className);
10207 * 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)
10208 * @param {String} className
10209 * @return {Roo.Element} this
10211 addClassOnClick : function(className){
10212 var dom = this.dom;
10213 this.on("mousedown", function(){
10214 Roo.fly(dom, '_internal').addClass(className);
10215 var d = Roo.get(document);
10216 var fn = function(){
10217 Roo.fly(dom, '_internal').removeClass(className);
10218 d.removeListener("mouseup", fn);
10220 d.on("mouseup", fn);
10226 * Stops the specified event from bubbling and optionally prevents the default action
10227 * @param {String} eventName
10228 * @param {Boolean} preventDefault (optional) true to prevent the default action too
10229 * @return {Roo.Element} this
10231 swallowEvent : function(eventName, preventDefault){
10232 var fn = function(e){
10233 e.stopPropagation();
10234 if(preventDefault){
10235 e.preventDefault();
10238 if(eventName instanceof Array){
10239 for(var i = 0, len = eventName.length; i < len; i++){
10240 this.on(eventName[i], fn);
10244 this.on(eventName, fn);
10251 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
10254 * Sizes this element to its parent element's dimensions performing
10255 * neccessary box adjustments.
10256 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
10257 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
10258 * @return {Roo.Element} this
10260 fitToParent : function(monitorResize, targetParent) {
10261 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
10262 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
10263 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
10266 var p = Roo.get(targetParent || this.dom.parentNode);
10267 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
10268 if (monitorResize === true) {
10269 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
10270 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
10276 * Gets the next sibling, skipping text nodes
10277 * @return {HTMLElement} The next sibling or null
10279 getNextSibling : function(){
10280 var n = this.dom.nextSibling;
10281 while(n && n.nodeType != 1){
10288 * Gets the previous sibling, skipping text nodes
10289 * @return {HTMLElement} The previous sibling or null
10291 getPrevSibling : function(){
10292 var n = this.dom.previousSibling;
10293 while(n && n.nodeType != 1){
10294 n = n.previousSibling;
10301 * Appends the passed element(s) to this element
10302 * @param {String/HTMLElement/Array/Element/CompositeElement} el
10303 * @return {Roo.Element} this
10305 appendChild: function(el){
10312 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
10313 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
10314 * automatically generated with the specified attributes.
10315 * @param {HTMLElement} insertBefore (optional) a child element of this element
10316 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
10317 * @return {Roo.Element} The new child element
10319 createChild: function(config, insertBefore, returnDom){
10320 config = config || {tag:'div'};
10322 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
10324 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
10328 * Appends this element to the passed element
10329 * @param {String/HTMLElement/Element} el The new parent element
10330 * @return {Roo.Element} this
10332 appendTo: function(el){
10333 el = Roo.getDom(el);
10334 el.appendChild(this.dom);
10339 * Inserts this element before the passed element in the DOM
10340 * @param {String/HTMLElement/Element} el The element to insert before
10341 * @return {Roo.Element} this
10343 insertBefore: function(el){
10344 el = Roo.getDom(el);
10345 el.parentNode.insertBefore(this.dom, el);
10350 * Inserts this element after the passed element in the DOM
10351 * @param {String/HTMLElement/Element} el The element to insert after
10352 * @return {Roo.Element} this
10354 insertAfter: function(el){
10355 el = Roo.getDom(el);
10356 el.parentNode.insertBefore(this.dom, el.nextSibling);
10361 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
10362 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
10363 * @return {Roo.Element} The new child
10365 insertFirst: function(el, returnDom){
10367 if(typeof el == 'object' && !el.nodeType){ // dh config
10368 return this.createChild(el, this.dom.firstChild, returnDom);
10370 el = Roo.getDom(el);
10371 this.dom.insertBefore(el, this.dom.firstChild);
10372 return !returnDom ? Roo.get(el) : el;
10377 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
10378 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
10379 * @param {String} where (optional) 'before' or 'after' defaults to before
10380 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
10381 * @return {Roo.Element} the inserted Element
10383 insertSibling: function(el, where, returnDom){
10384 where = where ? where.toLowerCase() : 'before';
10386 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
10388 if(typeof el == 'object' && !el.nodeType){ // dh config
10389 if(where == 'after' && !this.dom.nextSibling){
10390 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
10392 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
10396 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
10397 where == 'before' ? this.dom : this.dom.nextSibling);
10406 * Creates and wraps this element with another element
10407 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
10408 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
10409 * @return {HTMLElement/Element} The newly created wrapper element
10411 wrap: function(config, returnDom){
10413 config = {tag: "div"};
10415 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
10416 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
10421 * Replaces the passed element with this element
10422 * @param {String/HTMLElement/Element} el The element to replace
10423 * @return {Roo.Element} this
10425 replace: function(el){
10427 this.insertBefore(el);
10433 * Inserts an html fragment into this element
10434 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
10435 * @param {String} html The HTML fragment
10436 * @param {Boolean} returnEl True to return an Roo.Element
10437 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
10439 insertHtml : function(where, html, returnEl){
10440 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
10441 return returnEl ? Roo.get(el) : el;
10445 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
10446 * @param {Object} o The object with the attributes
10447 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
10448 * @return {Roo.Element} this
10450 set : function(o, useSet){
10452 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
10453 for(var attr in o){
10454 if(attr == "style" || typeof o[attr] == "function") { continue; }
10456 el.className = o["cls"];
10459 el.setAttribute(attr, o[attr]);
10461 el[attr] = o[attr];
10466 Roo.DomHelper.applyStyles(el, o.style);
10472 * Convenience method for constructing a KeyMap
10473 * @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:
10474 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
10475 * @param {Function} fn The function to call
10476 * @param {Object} scope (optional) The scope of the function
10477 * @return {Roo.KeyMap} The KeyMap created
10479 addKeyListener : function(key, fn, scope){
10481 if(typeof key != "object" || key instanceof Array){
10497 return new Roo.KeyMap(this, config);
10501 * Creates a KeyMap for this element
10502 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
10503 * @return {Roo.KeyMap} The KeyMap created
10505 addKeyMap : function(config){
10506 return new Roo.KeyMap(this, config);
10510 * Returns true if this element is scrollable.
10511 * @return {Boolean}
10513 isScrollable : function(){
10514 var dom = this.dom;
10515 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
10519 * 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().
10520 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
10521 * @param {Number} value The new scroll value
10522 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
10523 * @return {Element} this
10526 scrollTo : function(side, value, animate){
10527 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
10528 if(!animate || !A){
10529 this.dom[prop] = value;
10531 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
10532 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
10538 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
10539 * within this element's scrollable range.
10540 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
10541 * @param {Number} distance How far to scroll the element in pixels
10542 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
10543 * @return {Boolean} Returns true if a scroll was triggered or false if the element
10544 * was scrolled as far as it could go.
10546 scroll : function(direction, distance, animate){
10547 if(!this.isScrollable()){
10551 var l = el.scrollLeft, t = el.scrollTop;
10552 var w = el.scrollWidth, h = el.scrollHeight;
10553 var cw = el.clientWidth, ch = el.clientHeight;
10554 direction = direction.toLowerCase();
10555 var scrolled = false;
10556 var a = this.preanim(arguments, 2);
10561 var v = Math.min(l + distance, w-cw);
10562 this.scrollTo("left", v, a);
10569 var v = Math.max(l - distance, 0);
10570 this.scrollTo("left", v, a);
10578 var v = Math.max(t - distance, 0);
10579 this.scrollTo("top", v, a);
10587 var v = Math.min(t + distance, h-ch);
10588 this.scrollTo("top", v, a);
10597 * Translates the passed page coordinates into left/top css values for this element
10598 * @param {Number/Array} x The page x or an array containing [x, y]
10599 * @param {Number} y The page y
10600 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
10602 translatePoints : function(x, y){
10603 if(typeof x == 'object' || x instanceof Array){
10604 y = x[1]; x = x[0];
10606 var p = this.getStyle('position');
10607 var o = this.getXY();
10609 var l = parseInt(this.getStyle('left'), 10);
10610 var t = parseInt(this.getStyle('top'), 10);
10613 l = (p == "relative") ? 0 : this.dom.offsetLeft;
10616 t = (p == "relative") ? 0 : this.dom.offsetTop;
10619 return {left: (x - o[0] + l), top: (y - o[1] + t)};
10623 * Returns the current scroll position of the element.
10624 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
10626 getScroll : function(){
10627 var d = this.dom, doc = document;
10628 if(d == doc || d == doc.body){
10629 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
10630 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
10631 return {left: l, top: t};
10633 return {left: d.scrollLeft, top: d.scrollTop};
10638 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
10639 * are convert to standard 6 digit hex color.
10640 * @param {String} attr The css attribute
10641 * @param {String} defaultValue The default value to use when a valid color isn't found
10642 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
10645 getColor : function(attr, defaultValue, prefix){
10646 var v = this.getStyle(attr);
10647 if(!v || v == "transparent" || v == "inherit") {
10648 return defaultValue;
10650 var color = typeof prefix == "undefined" ? "#" : prefix;
10651 if(v.substr(0, 4) == "rgb("){
10652 var rvs = v.slice(4, v.length -1).split(",");
10653 for(var i = 0; i < 3; i++){
10654 var h = parseInt(rvs[i]).toString(16);
10661 if(v.substr(0, 1) == "#"){
10662 if(v.length == 4) {
10663 for(var i = 1; i < 4; i++){
10664 var c = v.charAt(i);
10667 }else if(v.length == 7){
10668 color += v.substr(1);
10672 return(color.length > 5 ? color.toLowerCase() : defaultValue);
10676 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
10677 * gradient background, rounded corners and a 4-way shadow.
10678 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
10679 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
10680 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
10681 * @return {Roo.Element} this
10683 boxWrap : function(cls){
10684 cls = cls || 'x-box';
10685 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
10686 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
10691 * Returns the value of a namespaced attribute from the element's underlying DOM node.
10692 * @param {String} namespace The namespace in which to look for the attribute
10693 * @param {String} name The attribute name
10694 * @return {String} The attribute value
10696 getAttributeNS : Roo.isIE ? function(ns, name){
10698 var type = typeof d[ns+":"+name];
10699 if(type != 'undefined' && type != 'unknown'){
10700 return d[ns+":"+name];
10703 } : function(ns, name){
10705 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
10710 * Sets or Returns the value the dom attribute value
10711 * @param {String|Object} name The attribute name (or object to set multiple attributes)
10712 * @param {String} value (optional) The value to set the attribute to
10713 * @return {String} The attribute value
10715 attr : function(name){
10716 if (arguments.length > 1) {
10717 this.dom.setAttribute(name, arguments[1]);
10718 return arguments[1];
10720 if (typeof(name) == 'object') {
10721 for(var i in name) {
10722 this.attr(i, name[i]);
10728 if (!this.dom.hasAttribute(name)) {
10731 return this.dom.getAttribute(name);
10738 var ep = El.prototype;
10741 * Appends an event handler (Shorthand for addListener)
10742 * @param {String} eventName The type of event to append
10743 * @param {Function} fn The method the event invokes
10744 * @param {Object} scope (optional) The scope (this object) of the fn
10745 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
10748 ep.on = ep.addListener;
10749 // backwards compat
10750 ep.mon = ep.addListener;
10753 * Removes an event handler from this element (shorthand for removeListener)
10754 * @param {String} eventName the type of event to remove
10755 * @param {Function} fn the method the event invokes
10756 * @return {Roo.Element} this
10759 ep.un = ep.removeListener;
10762 * true to automatically adjust width and height settings for box-model issues (default to true)
10764 ep.autoBoxAdjust = true;
10767 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
10770 El.addUnits = function(v, defaultUnit){
10771 if(v === "" || v == "auto"){
10774 if(v === undefined){
10777 if(typeof v == "number" || !El.unitPattern.test(v)){
10778 return v + (defaultUnit || 'px');
10783 // special markup used throughout Roo when box wrapping elements
10784 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>';
10786 * Visibility mode constant - Use visibility to hide element
10792 * Visibility mode constant - Use display to hide element
10798 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
10799 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
10800 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
10812 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
10813 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
10814 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
10815 * @return {Element} The Element object
10818 El.get = function(el){
10820 if(!el){ return null; }
10821 if(typeof el == "string"){ // element id
10822 if(!(elm = document.getElementById(el))){
10825 if(ex = El.cache[el]){
10828 ex = El.cache[el] = new El(elm);
10831 }else if(el.tagName){ // dom element
10835 if(ex = El.cache[id]){
10838 ex = El.cache[id] = new El(el);
10841 }else if(el instanceof El){
10843 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
10844 // catch case where it hasn't been appended
10845 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
10848 }else if(el.isComposite){
10850 }else if(el instanceof Array){
10851 return El.select(el);
10852 }else if(el == document){
10853 // create a bogus element object representing the document object
10855 var f = function(){};
10856 f.prototype = El.prototype;
10858 docEl.dom = document;
10866 El.uncache = function(el){
10867 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
10869 delete El.cache[a[i].id || a[i]];
10875 // Garbage collection - uncache elements/purge listeners on orphaned elements
10876 // so we don't hold a reference and cause the browser to retain them
10877 El.garbageCollect = function(){
10878 if(!Roo.enableGarbageCollector){
10879 clearInterval(El.collectorThread);
10882 for(var eid in El.cache){
10883 var el = El.cache[eid], d = el.dom;
10884 // -------------------------------------------------------
10885 // Determining what is garbage:
10886 // -------------------------------------------------------
10888 // dom node is null, definitely garbage
10889 // -------------------------------------------------------
10891 // no parentNode == direct orphan, definitely garbage
10892 // -------------------------------------------------------
10893 // !d.offsetParent && !document.getElementById(eid)
10894 // display none elements have no offsetParent so we will
10895 // also try to look it up by it's id. However, check
10896 // offsetParent first so we don't do unneeded lookups.
10897 // This enables collection of elements that are not orphans
10898 // directly, but somewhere up the line they have an orphan
10900 // -------------------------------------------------------
10901 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
10902 delete El.cache[eid];
10903 if(d && Roo.enableListenerCollection){
10909 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
10913 El.Flyweight = function(dom){
10916 El.Flyweight.prototype = El.prototype;
10918 El._flyweights = {};
10920 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
10921 * the dom node can be overwritten by other code.
10922 * @param {String/HTMLElement} el The dom node or id
10923 * @param {String} named (optional) Allows for creation of named reusable flyweights to
10924 * prevent conflicts (e.g. internally Roo uses "_internal")
10926 * @return {Element} The shared Element object
10928 El.fly = function(el, named){
10929 named = named || '_global';
10930 el = Roo.getDom(el);
10934 if(!El._flyweights[named]){
10935 El._flyweights[named] = new El.Flyweight();
10937 El._flyweights[named].dom = el;
10938 return El._flyweights[named];
10942 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
10943 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
10944 * Shorthand of {@link Roo.Element#get}
10945 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
10946 * @return {Element} The Element object
10952 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
10953 * the dom node can be overwritten by other code.
10954 * Shorthand of {@link Roo.Element#fly}
10955 * @param {String/HTMLElement} el The dom node or id
10956 * @param {String} named (optional) Allows for creation of named reusable flyweights to
10957 * prevent conflicts (e.g. internally Roo uses "_internal")
10959 * @return {Element} The shared Element object
10965 // speedy lookup for elements never to box adjust
10966 var noBoxAdjust = Roo.isStrict ? {
10969 input:1, select:1, textarea:1
10971 if(Roo.isIE || Roo.isGecko){
10972 noBoxAdjust['button'] = 1;
10976 Roo.EventManager.on(window, 'unload', function(){
10978 delete El._flyweights;
10986 Roo.Element.selectorFunction = Roo.DomQuery.select;
10989 Roo.Element.select = function(selector, unique, root){
10991 if(typeof selector == "string"){
10992 els = Roo.Element.selectorFunction(selector, root);
10993 }else if(selector.length !== undefined){
10996 throw "Invalid selector";
10998 if(unique === true){
10999 return new Roo.CompositeElement(els);
11001 return new Roo.CompositeElementLite(els);
11005 * Selects elements based on the passed CSS selector to enable working on them as 1.
11006 * @param {String/Array} selector The CSS selector or an array of elements
11007 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
11008 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
11009 * @return {CompositeElementLite/CompositeElement}
11013 Roo.select = Roo.Element.select;
11030 * Ext JS Library 1.1.1
11031 * Copyright(c) 2006-2007, Ext JS, LLC.
11033 * Originally Released Under LGPL - original licence link has changed is not relivant.
11036 * <script type="text/javascript">
11041 //Notifies Element that fx methods are available
11042 Roo.enableFx = true;
11046 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
11047 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
11048 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
11049 * Element effects to work.</p><br/>
11051 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
11052 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
11053 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
11054 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
11055 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
11056 * expected results and should be done with care.</p><br/>
11058 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
11059 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
11062 ----- -----------------------------
11063 tl The top left corner
11064 t The center of the top edge
11065 tr The top right corner
11066 l The center of the left edge
11067 r The center of the right edge
11068 bl The bottom left corner
11069 b The center of the bottom edge
11070 br The bottom right corner
11072 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
11073 * below are common options that can be passed to any Fx method.</b>
11074 * @cfg {Function} callback A function called when the effect is finished
11075 * @cfg {Object} scope The scope of the effect function
11076 * @cfg {String} easing A valid Easing value for the effect
11077 * @cfg {String} afterCls A css class to apply after the effect
11078 * @cfg {Number} duration The length of time (in seconds) that the effect should last
11079 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
11080 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
11081 * effects that end with the element being visually hidden, ignored otherwise)
11082 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
11083 * a function which returns such a specification that will be applied to the Element after the effect finishes
11084 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
11085 * @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
11086 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
11090 * Slides the element into view. An anchor point can be optionally passed to set the point of
11091 * origin for the slide effect. This function automatically handles wrapping the element with
11092 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
11095 // default: slide the element in from the top
11098 // custom: slide the element in from the right with a 2-second duration
11099 el.slideIn('r', { duration: 2 });
11101 // common config options shown with default values
11107 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
11108 * @param {Object} options (optional) Object literal with any of the Fx config options
11109 * @return {Roo.Element} The Element
11111 slideIn : function(anchor, o){
11112 var el = this.getFxEl();
11115 el.queueFx(o, function(){
11117 anchor = anchor || "t";
11119 // fix display to visibility
11122 // restore values after effect
11123 var r = this.getFxRestore();
11124 var b = this.getBox();
11125 // fixed size for slide
11129 var wrap = this.fxWrap(r.pos, o, "hidden");
11131 var st = this.dom.style;
11132 st.visibility = "visible";
11133 st.position = "absolute";
11135 // clear out temp styles after slide and unwrap
11136 var after = function(){
11137 el.fxUnwrap(wrap, r.pos, o);
11138 st.width = r.width;
11139 st.height = r.height;
11142 // time to calc the positions
11143 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
11145 switch(anchor.toLowerCase()){
11147 wrap.setSize(b.width, 0);
11148 st.left = st.bottom = "0";
11152 wrap.setSize(0, b.height);
11153 st.right = st.top = "0";
11157 wrap.setSize(0, b.height);
11158 wrap.setX(b.right);
11159 st.left = st.top = "0";
11160 a = {width: bw, points: pt};
11163 wrap.setSize(b.width, 0);
11164 wrap.setY(b.bottom);
11165 st.left = st.top = "0";
11166 a = {height: bh, points: pt};
11169 wrap.setSize(0, 0);
11170 st.right = st.bottom = "0";
11171 a = {width: bw, height: bh};
11174 wrap.setSize(0, 0);
11175 wrap.setY(b.y+b.height);
11176 st.right = st.top = "0";
11177 a = {width: bw, height: bh, points: pt};
11180 wrap.setSize(0, 0);
11181 wrap.setXY([b.right, b.bottom]);
11182 st.left = st.top = "0";
11183 a = {width: bw, height: bh, points: pt};
11186 wrap.setSize(0, 0);
11187 wrap.setX(b.x+b.width);
11188 st.left = st.bottom = "0";
11189 a = {width: bw, height: bh, points: pt};
11192 this.dom.style.visibility = "visible";
11195 arguments.callee.anim = wrap.fxanim(a,
11205 * Slides the element out of view. An anchor point can be optionally passed to set the end point
11206 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
11207 * 'hidden') but block elements will still take up space in the document. The element must be removed
11208 * from the DOM using the 'remove' config option if desired. This function automatically handles
11209 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
11212 // default: slide the element out to the top
11215 // custom: slide the element out to the right with a 2-second duration
11216 el.slideOut('r', { duration: 2 });
11218 // common config options shown with default values
11226 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
11227 * @param {Object} options (optional) Object literal with any of the Fx config options
11228 * @return {Roo.Element} The Element
11230 slideOut : function(anchor, o){
11231 var el = this.getFxEl();
11234 el.queueFx(o, function(){
11236 anchor = anchor || "t";
11238 // restore values after effect
11239 var r = this.getFxRestore();
11241 var b = this.getBox();
11242 // fixed size for slide
11246 var wrap = this.fxWrap(r.pos, o, "visible");
11248 var st = this.dom.style;
11249 st.visibility = "visible";
11250 st.position = "absolute";
11254 var after = function(){
11256 el.setDisplayed(false);
11261 el.fxUnwrap(wrap, r.pos, o);
11263 st.width = r.width;
11264 st.height = r.height;
11269 var a, zero = {to: 0};
11270 switch(anchor.toLowerCase()){
11272 st.left = st.bottom = "0";
11273 a = {height: zero};
11276 st.right = st.top = "0";
11280 st.left = st.top = "0";
11281 a = {width: zero, points: {to:[b.right, b.y]}};
11284 st.left = st.top = "0";
11285 a = {height: zero, points: {to:[b.x, b.bottom]}};
11288 st.right = st.bottom = "0";
11289 a = {width: zero, height: zero};
11292 st.right = st.top = "0";
11293 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
11296 st.left = st.top = "0";
11297 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
11300 st.left = st.bottom = "0";
11301 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
11305 arguments.callee.anim = wrap.fxanim(a,
11315 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
11316 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
11317 * The element must be removed from the DOM using the 'remove' config option if desired.
11323 // common config options shown with default values
11331 * @param {Object} options (optional) Object literal with any of the Fx config options
11332 * @return {Roo.Element} The Element
11334 puff : function(o){
11335 var el = this.getFxEl();
11338 el.queueFx(o, function(){
11339 this.clearOpacity();
11342 // restore values after effect
11343 var r = this.getFxRestore();
11344 var st = this.dom.style;
11346 var after = function(){
11348 el.setDisplayed(false);
11355 el.setPositioning(r.pos);
11356 st.width = r.width;
11357 st.height = r.height;
11362 var width = this.getWidth();
11363 var height = this.getHeight();
11365 arguments.callee.anim = this.fxanim({
11366 width : {to: this.adjustWidth(width * 2)},
11367 height : {to: this.adjustHeight(height * 2)},
11368 points : {by: [-(width * .5), -(height * .5)]},
11370 fontSize: {to:200, unit: "%"}
11381 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
11382 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
11383 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
11389 // all config options shown with default values
11397 * @param {Object} options (optional) Object literal with any of the Fx config options
11398 * @return {Roo.Element} The Element
11400 switchOff : function(o){
11401 var el = this.getFxEl();
11404 el.queueFx(o, function(){
11405 this.clearOpacity();
11408 // restore values after effect
11409 var r = this.getFxRestore();
11410 var st = this.dom.style;
11412 var after = function(){
11414 el.setDisplayed(false);
11420 el.setPositioning(r.pos);
11421 st.width = r.width;
11422 st.height = r.height;
11427 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
11428 this.clearOpacity();
11432 points:{by:[0, this.getHeight() * .5]}
11433 }, o, 'motion', 0.3, 'easeIn', after);
11434 }).defer(100, this);
11441 * Highlights the Element by setting a color (applies to the background-color by default, but can be
11442 * changed using the "attr" config option) and then fading back to the original color. If no original
11443 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
11446 // default: highlight background to yellow
11449 // custom: highlight foreground text to blue for 2 seconds
11450 el.highlight("0000ff", { attr: 'color', duration: 2 });
11452 // common config options shown with default values
11453 el.highlight("ffff9c", {
11454 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
11455 endColor: (current color) or "ffffff",
11460 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
11461 * @param {Object} options (optional) Object literal with any of the Fx config options
11462 * @return {Roo.Element} The Element
11464 highlight : function(color, o){
11465 var el = this.getFxEl();
11468 el.queueFx(o, function(){
11469 color = color || "ffff9c";
11470 attr = o.attr || "backgroundColor";
11472 this.clearOpacity();
11475 var origColor = this.getColor(attr);
11476 var restoreColor = this.dom.style[attr];
11477 endColor = (o.endColor || origColor) || "ffffff";
11479 var after = function(){
11480 el.dom.style[attr] = restoreColor;
11485 a[attr] = {from: color, to: endColor};
11486 arguments.callee.anim = this.fxanim(a,
11496 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
11499 // default: a single light blue ripple
11502 // custom: 3 red ripples lasting 3 seconds total
11503 el.frame("ff0000", 3, { duration: 3 });
11505 // common config options shown with default values
11506 el.frame("C3DAF9", 1, {
11507 duration: 1 //duration of entire animation (not each individual ripple)
11508 // Note: Easing is not configurable and will be ignored if included
11511 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
11512 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
11513 * @param {Object} options (optional) Object literal with any of the Fx config options
11514 * @return {Roo.Element} The Element
11516 frame : function(color, count, o){
11517 var el = this.getFxEl();
11520 el.queueFx(o, function(){
11521 color = color || "#C3DAF9";
11522 if(color.length == 6){
11523 color = "#" + color;
11525 count = count || 1;
11526 duration = o.duration || 1;
11529 var b = this.getBox();
11530 var animFn = function(){
11531 var proxy = this.createProxy({
11534 visbility:"hidden",
11535 position:"absolute",
11536 "z-index":"35000", // yee haw
11537 border:"0px solid " + color
11540 var scale = Roo.isBorderBox ? 2 : 1;
11542 top:{from:b.y, to:b.y - 20},
11543 left:{from:b.x, to:b.x - 20},
11544 borderWidth:{from:0, to:10},
11545 opacity:{from:1, to:0},
11546 height:{from:b.height, to:(b.height + (20*scale))},
11547 width:{from:b.width, to:(b.width + (20*scale))}
11548 }, duration, function(){
11552 animFn.defer((duration/2)*1000, this);
11563 * Creates a pause before any subsequent queued effects begin. If there are
11564 * no effects queued after the pause it will have no effect.
11569 * @param {Number} seconds The length of time to pause (in seconds)
11570 * @return {Roo.Element} The Element
11572 pause : function(seconds){
11573 var el = this.getFxEl();
11576 el.queueFx(o, function(){
11577 setTimeout(function(){
11579 }, seconds * 1000);
11585 * Fade an element in (from transparent to opaque). The ending opacity can be specified
11586 * using the "endOpacity" config option.
11589 // default: fade in from opacity 0 to 100%
11592 // custom: fade in from opacity 0 to 75% over 2 seconds
11593 el.fadeIn({ endOpacity: .75, duration: 2});
11595 // common config options shown with default values
11597 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
11602 * @param {Object} options (optional) Object literal with any of the Fx config options
11603 * @return {Roo.Element} The Element
11605 fadeIn : function(o){
11606 var el = this.getFxEl();
11608 el.queueFx(o, function(){
11609 this.setOpacity(0);
11611 this.dom.style.visibility = 'visible';
11612 var to = o.endOpacity || 1;
11613 arguments.callee.anim = this.fxanim({opacity:{to:to}},
11614 o, null, .5, "easeOut", function(){
11616 this.clearOpacity();
11625 * Fade an element out (from opaque to transparent). The ending opacity can be specified
11626 * using the "endOpacity" config option.
11629 // default: fade out from the element's current opacity to 0
11632 // custom: fade out from the element's current opacity to 25% over 2 seconds
11633 el.fadeOut({ endOpacity: .25, duration: 2});
11635 // common config options shown with default values
11637 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
11644 * @param {Object} options (optional) Object literal with any of the Fx config options
11645 * @return {Roo.Element} The Element
11647 fadeOut : function(o){
11648 var el = this.getFxEl();
11650 el.queueFx(o, function(){
11651 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
11652 o, null, .5, "easeOut", function(){
11653 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
11654 this.dom.style.display = "none";
11656 this.dom.style.visibility = "hidden";
11658 this.clearOpacity();
11666 * Animates the transition of an element's dimensions from a starting height/width
11667 * to an ending height/width.
11670 // change height and width to 100x100 pixels
11671 el.scale(100, 100);
11673 // common config options shown with default values. The height and width will default to
11674 // the element's existing values if passed as null.
11677 [element's height], {
11682 * @param {Number} width The new width (pass undefined to keep the original width)
11683 * @param {Number} height The new height (pass undefined to keep the original height)
11684 * @param {Object} options (optional) Object literal with any of the Fx config options
11685 * @return {Roo.Element} The Element
11687 scale : function(w, h, o){
11688 this.shift(Roo.apply({}, o, {
11696 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
11697 * Any of these properties not specified in the config object will not be changed. This effect
11698 * requires that at least one new dimension, position or opacity setting must be passed in on
11699 * the config object in order for the function to have any effect.
11702 // slide the element horizontally to x position 200 while changing the height and opacity
11703 el.shift({ x: 200, height: 50, opacity: .8 });
11705 // common config options shown with default values.
11707 width: [element's width],
11708 height: [element's height],
11709 x: [element's x position],
11710 y: [element's y position],
11711 opacity: [element's opacity],
11716 * @param {Object} options Object literal with any of the Fx config options
11717 * @return {Roo.Element} The Element
11719 shift : function(o){
11720 var el = this.getFxEl();
11722 el.queueFx(o, function(){
11723 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
11724 if(w !== undefined){
11725 a.width = {to: this.adjustWidth(w)};
11727 if(h !== undefined){
11728 a.height = {to: this.adjustHeight(h)};
11730 if(x !== undefined || y !== undefined){
11732 x !== undefined ? x : this.getX(),
11733 y !== undefined ? y : this.getY()
11736 if(op !== undefined){
11737 a.opacity = {to: op};
11739 if(o.xy !== undefined){
11740 a.points = {to: o.xy};
11742 arguments.callee.anim = this.fxanim(a,
11743 o, 'motion', .35, "easeOut", function(){
11751 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
11752 * ending point of the effect.
11755 // default: slide the element downward while fading out
11758 // custom: slide the element out to the right with a 2-second duration
11759 el.ghost('r', { duration: 2 });
11761 // common config options shown with default values
11769 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
11770 * @param {Object} options (optional) Object literal with any of the Fx config options
11771 * @return {Roo.Element} The Element
11773 ghost : function(anchor, o){
11774 var el = this.getFxEl();
11777 el.queueFx(o, function(){
11778 anchor = anchor || "b";
11780 // restore values after effect
11781 var r = this.getFxRestore();
11782 var w = this.getWidth(),
11783 h = this.getHeight();
11785 var st = this.dom.style;
11787 var after = function(){
11789 el.setDisplayed(false);
11795 el.setPositioning(r.pos);
11796 st.width = r.width;
11797 st.height = r.height;
11802 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
11803 switch(anchor.toLowerCase()){
11830 arguments.callee.anim = this.fxanim(a,
11840 * Ensures that all effects queued after syncFx is called on the element are
11841 * run concurrently. This is the opposite of {@link #sequenceFx}.
11842 * @return {Roo.Element} The Element
11844 syncFx : function(){
11845 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
11854 * Ensures that all effects queued after sequenceFx is called on the element are
11855 * run in sequence. This is the opposite of {@link #syncFx}.
11856 * @return {Roo.Element} The Element
11858 sequenceFx : function(){
11859 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
11861 concurrent : false,
11868 nextFx : function(){
11869 var ef = this.fxQueue[0];
11876 * Returns true if the element has any effects actively running or queued, else returns false.
11877 * @return {Boolean} True if element has active effects, else false
11879 hasActiveFx : function(){
11880 return this.fxQueue && this.fxQueue[0];
11884 * Stops any running effects and clears the element's internal effects queue if it contains
11885 * any additional effects that haven't started yet.
11886 * @return {Roo.Element} The Element
11888 stopFx : function(){
11889 if(this.hasActiveFx()){
11890 var cur = this.fxQueue[0];
11891 if(cur && cur.anim && cur.anim.isAnimated()){
11892 this.fxQueue = [cur]; // clear out others
11893 cur.anim.stop(true);
11900 beforeFx : function(o){
11901 if(this.hasActiveFx() && !o.concurrent){
11912 * Returns true if the element is currently blocking so that no other effect can be queued
11913 * until this effect is finished, else returns false if blocking is not set. This is commonly
11914 * used to ensure that an effect initiated by a user action runs to completion prior to the
11915 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
11916 * @return {Boolean} True if blocking, else false
11918 hasFxBlock : function(){
11919 var q = this.fxQueue;
11920 return q && q[0] && q[0].block;
11924 queueFx : function(o, fn){
11928 if(!this.hasFxBlock()){
11929 Roo.applyIf(o, this.fxDefaults);
11931 var run = this.beforeFx(o);
11932 fn.block = o.block;
11933 this.fxQueue.push(fn);
11945 fxWrap : function(pos, o, vis){
11947 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
11950 wrapXY = this.getXY();
11952 var div = document.createElement("div");
11953 div.style.visibility = vis;
11954 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
11955 wrap.setPositioning(pos);
11956 if(wrap.getStyle("position") == "static"){
11957 wrap.position("relative");
11959 this.clearPositioning('auto');
11961 wrap.dom.appendChild(this.dom);
11963 wrap.setXY(wrapXY);
11970 fxUnwrap : function(wrap, pos, o){
11971 this.clearPositioning();
11972 this.setPositioning(pos);
11974 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
11980 getFxRestore : function(){
11981 var st = this.dom.style;
11982 return {pos: this.getPositioning(), width: st.width, height : st.height};
11986 afterFx : function(o){
11988 this.applyStyles(o.afterStyle);
11991 this.addClass(o.afterCls);
11993 if(o.remove === true){
11996 Roo.callback(o.callback, o.scope, [this]);
11998 this.fxQueue.shift();
12004 getFxEl : function(){ // support for composite element fx
12005 return Roo.get(this.dom);
12009 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
12010 animType = animType || 'run';
12012 var anim = Roo.lib.Anim[animType](
12014 (opt.duration || defaultDur) || .35,
12015 (opt.easing || defaultEase) || 'easeOut',
12017 Roo.callback(cb, this);
12026 // backwords compat
12027 Roo.Fx.resize = Roo.Fx.scale;
12029 //When included, Roo.Fx is automatically applied to Element so that all basic
12030 //effects are available directly via the Element API
12031 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
12033 * Ext JS Library 1.1.1
12034 * Copyright(c) 2006-2007, Ext JS, LLC.
12036 * Originally Released Under LGPL - original licence link has changed is not relivant.
12039 * <script type="text/javascript">
12044 * @class Roo.CompositeElement
12045 * Standard composite class. Creates a Roo.Element for every element in the collection.
12047 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
12048 * actions will be performed on all the elements in this collection.</b>
12050 * All methods return <i>this</i> and can be chained.
12052 var els = Roo.select("#some-el div.some-class", true);
12053 // or select directly from an existing element
12054 var el = Roo.get('some-el');
12055 el.select('div.some-class', true);
12057 els.setWidth(100); // all elements become 100 width
12058 els.hide(true); // all elements fade out and hide
12060 els.setWidth(100).hide(true);
12063 Roo.CompositeElement = function(els){
12064 this.elements = [];
12065 this.addElements(els);
12067 Roo.CompositeElement.prototype = {
12069 addElements : function(els){
12073 if(typeof els == "string"){
12074 els = Roo.Element.selectorFunction(els);
12076 var yels = this.elements;
12077 var index = yels.length-1;
12078 for(var i = 0, len = els.length; i < len; i++) {
12079 yels[++index] = Roo.get(els[i]);
12085 * Clears this composite and adds the elements returned by the passed selector.
12086 * @param {String/Array} els A string CSS selector, an array of elements or an element
12087 * @return {CompositeElement} this
12089 fill : function(els){
12090 this.elements = [];
12096 * Filters this composite to only elements that match the passed selector.
12097 * @param {String} selector A string CSS selector
12098 * @param {Boolean} inverse return inverse filter (not matches)
12099 * @return {CompositeElement} this
12101 filter : function(selector, inverse){
12103 inverse = inverse || false;
12104 this.each(function(el){
12105 var match = inverse ? !el.is(selector) : el.is(selector);
12107 els[els.length] = el.dom;
12114 invoke : function(fn, args){
12115 var els = this.elements;
12116 for(var i = 0, len = els.length; i < len; i++) {
12117 Roo.Element.prototype[fn].apply(els[i], args);
12122 * Adds elements to this composite.
12123 * @param {String/Array} els A string CSS selector, an array of elements or an element
12124 * @return {CompositeElement} this
12126 add : function(els){
12127 if(typeof els == "string"){
12128 this.addElements(Roo.Element.selectorFunction(els));
12129 }else if(els.length !== undefined){
12130 this.addElements(els);
12132 this.addElements([els]);
12137 * Calls the passed function passing (el, this, index) for each element in this composite.
12138 * @param {Function} fn The function to call
12139 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
12140 * @return {CompositeElement} this
12142 each : function(fn, scope){
12143 var els = this.elements;
12144 for(var i = 0, len = els.length; i < len; i++){
12145 if(fn.call(scope || els[i], els[i], this, i) === false) {
12153 * Returns the Element object at the specified index
12154 * @param {Number} index
12155 * @return {Roo.Element}
12157 item : function(index){
12158 return this.elements[index] || null;
12162 * Returns the first Element
12163 * @return {Roo.Element}
12165 first : function(){
12166 return this.item(0);
12170 * Returns the last Element
12171 * @return {Roo.Element}
12174 return this.item(this.elements.length-1);
12178 * Returns the number of elements in this composite
12181 getCount : function(){
12182 return this.elements.length;
12186 * Returns true if this composite contains the passed element
12189 contains : function(el){
12190 return this.indexOf(el) !== -1;
12194 * Returns true if this composite contains the passed element
12197 indexOf : function(el){
12198 return this.elements.indexOf(Roo.get(el));
12203 * Removes the specified element(s).
12204 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
12205 * or an array of any of those.
12206 * @param {Boolean} removeDom (optional) True to also remove the element from the document
12207 * @return {CompositeElement} this
12209 removeElement : function(el, removeDom){
12210 if(el instanceof Array){
12211 for(var i = 0, len = el.length; i < len; i++){
12212 this.removeElement(el[i]);
12216 var index = typeof el == 'number' ? el : this.indexOf(el);
12219 var d = this.elements[index];
12223 d.parentNode.removeChild(d);
12226 this.elements.splice(index, 1);
12232 * Replaces the specified element with the passed element.
12233 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
12235 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
12236 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
12237 * @return {CompositeElement} this
12239 replaceElement : function(el, replacement, domReplace){
12240 var index = typeof el == 'number' ? el : this.indexOf(el);
12243 this.elements[index].replaceWith(replacement);
12245 this.elements.splice(index, 1, Roo.get(replacement))
12252 * Removes all elements.
12254 clear : function(){
12255 this.elements = [];
12259 Roo.CompositeElement.createCall = function(proto, fnName){
12260 if(!proto[fnName]){
12261 proto[fnName] = function(){
12262 return this.invoke(fnName, arguments);
12266 for(var fnName in Roo.Element.prototype){
12267 if(typeof Roo.Element.prototype[fnName] == "function"){
12268 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
12274 * Ext JS Library 1.1.1
12275 * Copyright(c) 2006-2007, Ext JS, LLC.
12277 * Originally Released Under LGPL - original licence link has changed is not relivant.
12280 * <script type="text/javascript">
12284 * @class Roo.CompositeElementLite
12285 * @extends Roo.CompositeElement
12286 * Flyweight composite class. Reuses the same Roo.Element for element operations.
12288 var els = Roo.select("#some-el div.some-class");
12289 // or select directly from an existing element
12290 var el = Roo.get('some-el');
12291 el.select('div.some-class');
12293 els.setWidth(100); // all elements become 100 width
12294 els.hide(true); // all elements fade out and hide
12296 els.setWidth(100).hide(true);
12297 </code></pre><br><br>
12298 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
12299 * actions will be performed on all the elements in this collection.</b>
12301 Roo.CompositeElementLite = function(els){
12302 Roo.CompositeElementLite.superclass.constructor.call(this, els);
12303 this.el = new Roo.Element.Flyweight();
12305 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
12306 addElements : function(els){
12308 if(els instanceof Array){
12309 this.elements = this.elements.concat(els);
12311 var yels = this.elements;
12312 var index = yels.length-1;
12313 for(var i = 0, len = els.length; i < len; i++) {
12314 yels[++index] = els[i];
12320 invoke : function(fn, args){
12321 var els = this.elements;
12323 for(var i = 0, len = els.length; i < len; i++) {
12325 Roo.Element.prototype[fn].apply(el, args);
12330 * Returns a flyweight Element of the dom element object at the specified index
12331 * @param {Number} index
12332 * @return {Roo.Element}
12334 item : function(index){
12335 if(!this.elements[index]){
12338 this.el.dom = this.elements[index];
12342 // fixes scope with flyweight
12343 addListener : function(eventName, handler, scope, opt){
12344 var els = this.elements;
12345 for(var i = 0, len = els.length; i < len; i++) {
12346 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
12352 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
12353 * passed is the flyweight (shared) Roo.Element instance, so if you require a
12354 * a reference to the dom node, use el.dom.</b>
12355 * @param {Function} fn The function to call
12356 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
12357 * @return {CompositeElement} this
12359 each : function(fn, scope){
12360 var els = this.elements;
12362 for(var i = 0, len = els.length; i < len; i++){
12364 if(fn.call(scope || el, el, this, i) === false){
12371 indexOf : function(el){
12372 return this.elements.indexOf(Roo.getDom(el));
12375 replaceElement : function(el, replacement, domReplace){
12376 var index = typeof el == 'number' ? el : this.indexOf(el);
12378 replacement = Roo.getDom(replacement);
12380 var d = this.elements[index];
12381 d.parentNode.insertBefore(replacement, d);
12382 d.parentNode.removeChild(d);
12384 this.elements.splice(index, 1, replacement);
12389 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
12393 * Ext JS Library 1.1.1
12394 * Copyright(c) 2006-2007, Ext JS, LLC.
12396 * Originally Released Under LGPL - original licence link has changed is not relivant.
12399 * <script type="text/javascript">
12405 * @class Roo.data.Connection
12406 * @extends Roo.util.Observable
12407 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
12408 * either to a configured URL, or to a URL specified at request time.
12410 * Requests made by this class are asynchronous, and will return immediately. No data from
12411 * the server will be available to the statement immediately following the {@link #request} call.
12412 * To process returned data, use a callback in the request options object, or an event listener.
12414 * Note: If you are doing a file upload, you will not get a normal response object sent back to
12415 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
12416 * The response object is created using the innerHTML of the IFRAME's document as the responseText
12417 * property and, if present, the IFRAME's XML document as the responseXML property.
12419 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
12420 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
12421 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
12422 * standard DOM methods.
12424 * @param {Object} config a configuration object.
12426 Roo.data.Connection = function(config){
12427 Roo.apply(this, config);
12430 * @event beforerequest
12431 * Fires before a network request is made to retrieve a data object.
12432 * @param {Connection} conn This Connection object.
12433 * @param {Object} options The options config object passed to the {@link #request} method.
12435 "beforerequest" : true,
12437 * @event requestcomplete
12438 * Fires if the request was successfully completed.
12439 * @param {Connection} conn This Connection object.
12440 * @param {Object} response The XHR object containing the response data.
12441 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
12442 * @param {Object} options The options config object passed to the {@link #request} method.
12444 "requestcomplete" : true,
12446 * @event requestexception
12447 * Fires if an error HTTP status was returned from the server.
12448 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
12449 * @param {Connection} conn This Connection object.
12450 * @param {Object} response The XHR object containing the response data.
12451 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
12452 * @param {Object} options The options config object passed to the {@link #request} method.
12454 "requestexception" : true
12456 Roo.data.Connection.superclass.constructor.call(this);
12459 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
12461 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
12464 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
12465 * extra parameters to each request made by this object. (defaults to undefined)
12468 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
12469 * to each request made by this object. (defaults to undefined)
12472 * @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)
12475 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
12479 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
12485 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
12488 disableCaching: true,
12491 * Sends an HTTP request to a remote server.
12492 * @param {Object} options An object which may contain the following properties:<ul>
12493 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
12494 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
12495 * request, a url encoded string or a function to call to get either.</li>
12496 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
12497 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
12498 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
12499 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
12500 * <li>options {Object} The parameter to the request call.</li>
12501 * <li>success {Boolean} True if the request succeeded.</li>
12502 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
12504 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
12505 * The callback is passed the following parameters:<ul>
12506 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
12507 * <li>options {Object} The parameter to the request call.</li>
12509 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
12510 * The callback is passed the following parameters:<ul>
12511 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
12512 * <li>options {Object} The parameter to the request call.</li>
12514 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
12515 * for the callback function. Defaults to the browser window.</li>
12516 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
12517 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
12518 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
12519 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
12520 * params for the post data. Any params will be appended to the URL.</li>
12521 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
12523 * @return {Number} transactionId
12525 request : function(o){
12526 if(this.fireEvent("beforerequest", this, o) !== false){
12529 if(typeof p == "function"){
12530 p = p.call(o.scope||window, o);
12532 if(typeof p == "object"){
12533 p = Roo.urlEncode(o.params);
12535 if(this.extraParams){
12536 var extras = Roo.urlEncode(this.extraParams);
12537 p = p ? (p + '&' + extras) : extras;
12540 var url = o.url || this.url;
12541 if(typeof url == 'function'){
12542 url = url.call(o.scope||window, o);
12546 var form = Roo.getDom(o.form);
12547 url = url || form.action;
12549 var enctype = form.getAttribute("enctype");
12552 return this.doFormDataUpload(o, url);
12555 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
12556 return this.doFormUpload(o, p, url);
12558 var f = Roo.lib.Ajax.serializeForm(form);
12559 p = p ? (p + '&' + f) : f;
12562 if (!o.form && o.formData) {
12563 o.formData = o.formData === true ? new FormData() : o.formData;
12564 for (var k in o.params) {
12565 o.formData.append(k,o.params[k]);
12568 return this.doFormDataUpload(o, url);
12572 var hs = o.headers;
12573 if(this.defaultHeaders){
12574 hs = Roo.apply(hs || {}, this.defaultHeaders);
12581 success: this.handleResponse,
12582 failure: this.handleFailure,
12584 argument: {options: o},
12585 timeout : o.timeout || this.timeout
12588 var method = o.method||this.method||(p ? "POST" : "GET");
12590 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
12591 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
12594 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
12598 }else if(this.autoAbort !== false){
12602 if((method == 'GET' && p) || o.xmlData){
12603 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
12606 Roo.lib.Ajax.useDefaultHeader = typeof(o.headers) == 'undefined' || typeof(o.headers['Content-Type']) == 'undefined';
12607 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
12608 Roo.lib.Ajax.useDefaultHeader == true;
12609 return this.transId;
12611 Roo.callback(o.callback, o.scope, [o, null, null]);
12617 * Determine whether this object has a request outstanding.
12618 * @param {Number} transactionId (Optional) defaults to the last transaction
12619 * @return {Boolean} True if there is an outstanding request.
12621 isLoading : function(transId){
12623 return Roo.lib.Ajax.isCallInProgress(transId);
12625 return this.transId ? true : false;
12630 * Aborts any outstanding request.
12631 * @param {Number} transactionId (Optional) defaults to the last transaction
12633 abort : function(transId){
12634 if(transId || this.isLoading()){
12635 Roo.lib.Ajax.abort(transId || this.transId);
12640 handleResponse : function(response){
12641 this.transId = false;
12642 var options = response.argument.options;
12643 response.argument = options ? options.argument : null;
12644 this.fireEvent("requestcomplete", this, response, options);
12645 Roo.callback(options.success, options.scope, [response, options]);
12646 Roo.callback(options.callback, options.scope, [options, true, response]);
12650 handleFailure : function(response, e){
12651 this.transId = false;
12652 var options = response.argument.options;
12653 response.argument = options ? options.argument : null;
12654 this.fireEvent("requestexception", this, response, options, e);
12655 Roo.callback(options.failure, options.scope, [response, options]);
12656 Roo.callback(options.callback, options.scope, [options, false, response]);
12660 doFormUpload : function(o, ps, url){
12662 var frame = document.createElement('iframe');
12665 frame.className = 'x-hidden';
12667 frame.src = Roo.SSL_SECURE_URL;
12669 document.body.appendChild(frame);
12672 document.frames[id].name = id;
12675 var form = Roo.getDom(o.form);
12677 form.method = 'POST';
12678 form.enctype = form.encoding = 'multipart/form-data';
12684 if(ps){ // add dynamic params
12686 ps = Roo.urlDecode(ps, false);
12688 if(ps.hasOwnProperty(k)){
12689 hd = document.createElement('input');
12690 hd.type = 'hidden';
12693 form.appendChild(hd);
12700 var r = { // bogus response object
12705 r.argument = o ? o.argument : null;
12710 doc = frame.contentWindow.document;
12712 doc = (frame.contentDocument || window.frames[id].document);
12714 if(doc && doc.body){
12715 r.responseText = doc.body.innerHTML;
12717 if(doc && doc.XMLDocument){
12718 r.responseXML = doc.XMLDocument;
12720 r.responseXML = doc;
12727 Roo.EventManager.removeListener(frame, 'load', cb, this);
12729 this.fireEvent("requestcomplete", this, r, o);
12730 Roo.callback(o.success, o.scope, [r, o]);
12731 Roo.callback(o.callback, o.scope, [o, true, r]);
12733 setTimeout(function(){document.body.removeChild(frame);}, 100);
12736 Roo.EventManager.on(frame, 'load', cb, this);
12739 if(hiddens){ // remove dynamic params
12740 for(var i = 0, len = hiddens.length; i < len; i++){
12741 form.removeChild(hiddens[i]);
12745 // this is a 'formdata version???'
12748 doFormDataUpload : function(o, url)
12752 var form = Roo.getDom(o.form);
12753 form.enctype = form.encoding = 'multipart/form-data';
12754 formData = o.formData === true ? new FormData(form) : o.formData;
12756 formData = o.formData === true ? new FormData() : o.formData;
12761 success: this.handleResponse,
12762 failure: this.handleFailure,
12764 argument: {options: o},
12765 timeout : o.timeout || this.timeout
12768 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
12772 }else if(this.autoAbort !== false){
12776 //Roo.lib.Ajax.defaultPostHeader = null;
12777 Roo.lib.Ajax.useDefaultHeader = false;
12778 this.transId = Roo.lib.Ajax.request( "POST", url, cb, formData, o);
12779 Roo.lib.Ajax.useDefaultHeader = true;
12787 * Ext JS Library 1.1.1
12788 * Copyright(c) 2006-2007, Ext JS, LLC.
12790 * Originally Released Under LGPL - original licence link has changed is not relivant.
12793 * <script type="text/javascript">
12797 * Global Ajax request class.
12800 * @extends Roo.data.Connection
12803 * @cfg {String} url The default URL to be used for requests to the server. (defaults to undefined)
12804 * @cfg {Object} extraParams An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
12805 * @cfg {Object} defaultHeaders An object containing request headers which are added to each request made by this object. (defaults to undefined)
12806 * @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)
12807 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
12808 * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
12809 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
12811 Roo.Ajax = new Roo.data.Connection({
12820 * Serialize the passed form into a url encoded string
12822 * @param {String/HTMLElement} form
12825 serializeForm : function(form){
12826 return Roo.lib.Ajax.serializeForm(form);
12830 * Ext JS Library 1.1.1
12831 * Copyright(c) 2006-2007, Ext JS, LLC.
12833 * Originally Released Under LGPL - original licence link has changed is not relivant.
12836 * <script type="text/javascript">
12841 * @class Roo.UpdateManager
12842 * @extends Roo.util.Observable
12843 * Provides AJAX-style update for Element object.<br><br>
12846 * // Get it from a Roo.Element object
12847 * var el = Roo.get("foo");
12848 * var mgr = el.getUpdateManager();
12849 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
12851 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
12853 * // or directly (returns the same UpdateManager instance)
12854 * var mgr = new Roo.UpdateManager("myElementId");
12855 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
12856 * mgr.on("update", myFcnNeedsToKnow);
12858 // short handed call directly from the element object
12859 Roo.get("foo").load({
12863 text: "Loading Foo..."
12867 * Create new UpdateManager directly.
12868 * @param {String/HTMLElement/Roo.Element} el The element to update
12869 * @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).
12871 Roo.UpdateManager = function(el, forceNew){
12873 if(!forceNew && el.updateManager){
12874 return el.updateManager;
12877 * The Element object
12878 * @type Roo.Element
12882 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
12885 this.defaultUrl = null;
12889 * @event beforeupdate
12890 * Fired before an update is made, return false from your handler and the update is cancelled.
12891 * @param {Roo.Element} el
12892 * @param {String/Object/Function} url
12893 * @param {String/Object} params
12895 "beforeupdate": true,
12898 * Fired after successful update is made.
12899 * @param {Roo.Element} el
12900 * @param {Object} oResponseObject The response Object
12905 * Fired on update failure.
12906 * @param {Roo.Element} el
12907 * @param {Object} oResponseObject The response Object
12911 var d = Roo.UpdateManager.defaults;
12913 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
12916 this.sslBlankUrl = d.sslBlankUrl;
12918 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
12921 this.disableCaching = d.disableCaching;
12923 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
12926 this.indicatorText = d.indicatorText;
12928 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
12931 this.showLoadIndicator = d.showLoadIndicator;
12933 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
12936 this.timeout = d.timeout;
12939 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
12942 this.loadScripts = d.loadScripts;
12945 * Transaction object of current executing transaction
12947 this.transaction = null;
12952 this.autoRefreshProcId = null;
12954 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
12957 this.refreshDelegate = this.refresh.createDelegate(this);
12959 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
12962 this.updateDelegate = this.update.createDelegate(this);
12964 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
12967 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
12971 this.successDelegate = this.processSuccess.createDelegate(this);
12975 this.failureDelegate = this.processFailure.createDelegate(this);
12977 if(!this.renderer){
12979 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
12981 this.renderer = new Roo.UpdateManager.BasicRenderer();
12984 Roo.UpdateManager.superclass.constructor.call(this);
12987 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
12989 * Get the Element this UpdateManager is bound to
12990 * @return {Roo.Element} The element
12992 getEl : function(){
12996 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
12997 * @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:
13000 url: "your-url.php",<br/>
13001 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
13002 callback: yourFunction,<br/>
13003 scope: yourObject, //(optional scope) <br/>
13004 discardUrl: false, <br/>
13005 nocache: false,<br/>
13006 text: "Loading...",<br/>
13008 scripts: false<br/>
13011 * The only required property is url. The optional properties nocache, text and scripts
13012 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
13013 * @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}
13014 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
13015 * @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.
13017 update : function(url, params, callback, discardUrl){
13018 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
13019 var method = this.method,
13021 if(typeof url == "object"){ // must be config object
13024 params = params || cfg.params;
13025 callback = callback || cfg.callback;
13026 discardUrl = discardUrl || cfg.discardUrl;
13027 if(callback && cfg.scope){
13028 callback = callback.createDelegate(cfg.scope);
13030 if(typeof cfg.method != "undefined"){method = cfg.method;};
13031 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
13032 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
13033 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
13034 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
13036 this.showLoading();
13038 this.defaultUrl = url;
13040 if(typeof url == "function"){
13041 url = url.call(this);
13044 method = method || (params ? "POST" : "GET");
13045 if(method == "GET"){
13046 url = this.prepareUrl(url);
13049 var o = Roo.apply(cfg ||{}, {
13052 success: this.successDelegate,
13053 failure: this.failureDelegate,
13054 callback: undefined,
13055 timeout: (this.timeout*1000),
13056 argument: {"url": url, "form": null, "callback": callback, "params": params}
13058 Roo.log("updated manager called with timeout of " + o.timeout);
13059 this.transaction = Roo.Ajax.request(o);
13064 * 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.
13065 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
13066 * @param {String/HTMLElement} form The form Id or form element
13067 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
13068 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
13069 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
13071 formUpdate : function(form, url, reset, callback){
13072 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
13073 if(typeof url == "function"){
13074 url = url.call(this);
13076 form = Roo.getDom(form);
13077 this.transaction = Roo.Ajax.request({
13080 success: this.successDelegate,
13081 failure: this.failureDelegate,
13082 timeout: (this.timeout*1000),
13083 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
13085 this.showLoading.defer(1, this);
13090 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
13091 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
13093 refresh : function(callback){
13094 if(this.defaultUrl == null){
13097 this.update(this.defaultUrl, null, callback, true);
13101 * Set this element to auto refresh.
13102 * @param {Number} interval How often to update (in seconds).
13103 * @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)
13104 * @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}
13105 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
13106 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
13108 startAutoRefresh : function(interval, url, params, callback, refreshNow){
13110 this.update(url || this.defaultUrl, params, callback, true);
13112 if(this.autoRefreshProcId){
13113 clearInterval(this.autoRefreshProcId);
13115 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
13119 * Stop auto refresh on this element.
13121 stopAutoRefresh : function(){
13122 if(this.autoRefreshProcId){
13123 clearInterval(this.autoRefreshProcId);
13124 delete this.autoRefreshProcId;
13128 isAutoRefreshing : function(){
13129 return this.autoRefreshProcId ? true : false;
13132 * Called to update the element to "Loading" state. Override to perform custom action.
13134 showLoading : function(){
13135 if(this.showLoadIndicator){
13136 this.el.update(this.indicatorText);
13141 * Adds unique parameter to query string if disableCaching = true
13144 prepareUrl : function(url){
13145 if(this.disableCaching){
13146 var append = "_dc=" + (new Date().getTime());
13147 if(url.indexOf("?") !== -1){
13148 url += "&" + append;
13150 url += "?" + append;
13159 processSuccess : function(response){
13160 this.transaction = null;
13161 if(response.argument.form && response.argument.reset){
13162 try{ // put in try/catch since some older FF releases had problems with this
13163 response.argument.form.reset();
13166 if(this.loadScripts){
13167 this.renderer.render(this.el, response, this,
13168 this.updateComplete.createDelegate(this, [response]));
13170 this.renderer.render(this.el, response, this);
13171 this.updateComplete(response);
13175 updateComplete : function(response){
13176 this.fireEvent("update", this.el, response);
13177 if(typeof response.argument.callback == "function"){
13178 response.argument.callback(this.el, true, response);
13185 processFailure : function(response){
13186 this.transaction = null;
13187 this.fireEvent("failure", this.el, response);
13188 if(typeof response.argument.callback == "function"){
13189 response.argument.callback(this.el, false, response);
13194 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
13195 * @param {Object} renderer The object implementing the render() method
13197 setRenderer : function(renderer){
13198 this.renderer = renderer;
13201 getRenderer : function(){
13202 return this.renderer;
13206 * Set the defaultUrl used for updates
13207 * @param {String/Function} defaultUrl The url or a function to call to get the url
13209 setDefaultUrl : function(defaultUrl){
13210 this.defaultUrl = defaultUrl;
13214 * Aborts the executing transaction
13216 abort : function(){
13217 if(this.transaction){
13218 Roo.Ajax.abort(this.transaction);
13223 * Returns true if an update is in progress
13224 * @return {Boolean}
13226 isUpdating : function(){
13227 if(this.transaction){
13228 return Roo.Ajax.isLoading(this.transaction);
13235 * @class Roo.UpdateManager.defaults
13236 * @static (not really - but it helps the doc tool)
13237 * The defaults collection enables customizing the default properties of UpdateManager
13239 Roo.UpdateManager.defaults = {
13241 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
13247 * True to process scripts by default (Defaults to false).
13250 loadScripts : false,
13253 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
13256 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
13258 * Whether to append unique parameter on get request to disable caching (Defaults to false).
13261 disableCaching : false,
13263 * Whether to show indicatorText when loading (Defaults to true).
13266 showLoadIndicator : true,
13268 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
13271 indicatorText : '<div class="loading-indicator">Loading...</div>'
13275 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
13277 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
13278 * @param {String/HTMLElement/Roo.Element} el The element to update
13279 * @param {String} url The url
13280 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
13281 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
13284 * @member Roo.UpdateManager
13286 Roo.UpdateManager.updateElement = function(el, url, params, options){
13287 var um = Roo.get(el, true).getUpdateManager();
13288 Roo.apply(um, options);
13289 um.update(url, params, options ? options.callback : null);
13291 // alias for backwards compat
13292 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
13294 * @class Roo.UpdateManager.BasicRenderer
13295 * Default Content renderer. Updates the elements innerHTML with the responseText.
13297 Roo.UpdateManager.BasicRenderer = function(){};
13299 Roo.UpdateManager.BasicRenderer.prototype = {
13301 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
13302 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
13303 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
13304 * @param {Roo.Element} el The element being rendered
13305 * @param {Object} response The YUI Connect response object
13306 * @param {UpdateManager} updateManager The calling update manager
13307 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
13309 render : function(el, response, updateManager, callback){
13310 el.update(response.responseText, updateManager.loadScripts, callback);
13316 * (c)) Alan Knowles
13322 * @class Roo.DomTemplate
13323 * @extends Roo.Template
13324 * An effort at a dom based template engine..
13326 * Similar to XTemplate, except it uses dom parsing to create the template..
13328 * Supported features:
13333 {a_variable} - output encoded.
13334 {a_variable.format:("Y-m-d")} - call a method on the variable
13335 {a_variable:raw} - unencoded output
13336 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
13337 {a_variable:this.method_on_template(...)} - call a method on the template object.
13342 <div roo-for="a_variable or condition.."></div>
13343 <div roo-if="a_variable or condition"></div>
13344 <div roo-exec="some javascript"></div>
13345 <div roo-name="named_template"></div>
13350 Roo.DomTemplate = function()
13352 Roo.DomTemplate.superclass.constructor.apply(this, arguments);
13359 Roo.extend(Roo.DomTemplate, Roo.Template, {
13361 * id counter for sub templates.
13365 * flag to indicate if dom parser is inside a pre,
13366 * it will strip whitespace if not.
13371 * The various sub templates
13379 * basic tag replacing syntax
13382 * // you can fake an object call by doing this
13386 re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
13387 //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
13389 iterChild : function (node, method) {
13391 var oldPre = this.inPre;
13392 if (node.tagName == 'PRE') {
13395 for( var i = 0; i < node.childNodes.length; i++) {
13396 method.call(this, node.childNodes[i]);
13398 this.inPre = oldPre;
13404 * compile the template
13406 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
13409 compile: function()
13413 // covert the html into DOM...
13417 doc = document.implementation.createHTMLDocument("");
13418 doc.documentElement.innerHTML = this.html ;
13419 div = doc.documentElement;
13421 // old IE... - nasty -- it causes all sorts of issues.. with
13422 // images getting pulled from server..
13423 div = document.createElement('div');
13424 div.innerHTML = this.html;
13426 //doc.documentElement.innerHTML = htmlBody
13432 this.iterChild(div, function(n) {_t.compileNode(n, true); });
13434 var tpls = this.tpls;
13436 // create a top level template from the snippet..
13438 //Roo.log(div.innerHTML);
13445 body : div.innerHTML,
13458 Roo.each(tpls, function(tp){
13459 this.compileTpl(tp);
13460 this.tpls[tp.id] = tp;
13463 this.master = tpls[0];
13469 compileNode : function(node, istop) {
13474 // skip anything not a tag..
13475 if (node.nodeType != 1) {
13476 if (node.nodeType == 3 && !this.inPre) {
13477 // reduce white space..
13478 node.nodeValue = node.nodeValue.replace(/\s+/g, ' ');
13501 case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
13502 case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
13503 case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
13504 case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
13510 // just itterate children..
13511 this.iterChild(node,this.compileNode);
13514 tpl.uid = this.id++;
13515 tpl.value = node.getAttribute('roo-' + tpl.attr);
13516 node.removeAttribute('roo-'+ tpl.attr);
13517 if (tpl.attr != 'name') {
13518 var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
13519 node.parentNode.replaceChild(placeholder, node);
13522 var placeholder = document.createElement('span');
13523 placeholder.className = 'roo-tpl-' + tpl.value;
13524 node.parentNode.replaceChild(placeholder, node);
13527 // parent now sees '{domtplXXXX}
13528 this.iterChild(node,this.compileNode);
13530 // we should now have node body...
13531 var div = document.createElement('div');
13532 div.appendChild(node);
13534 // this has the unfortunate side effect of converting tagged attributes
13535 // eg. href="{...}" into %7C...%7D
13536 // this has been fixed by searching for those combo's although it's a bit hacky..
13539 tpl.body = div.innerHTML;
13546 switch (tpl.value) {
13547 case '.': tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
13548 case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
13549 default: tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
13554 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
13558 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
13562 tpl.id = tpl.value; // replace non characters???
13568 this.tpls.push(tpl);
13578 * Compile a segment of the template into a 'sub-template'
13584 compileTpl : function(tpl)
13586 var fm = Roo.util.Format;
13587 var useF = this.disableFormats !== true;
13589 var sep = Roo.isGecko ? "+\n" : ",\n";
13591 var undef = function(str) {
13592 Roo.debug && Roo.log("Property not found :" + str);
13596 //Roo.log(tpl.body);
13600 var fn = function(m, lbrace, name, format, args)
13603 //Roo.log(arguments);
13604 args = args ? args.replace(/\\'/g,"'") : args;
13605 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
13606 if (typeof(format) == 'undefined') {
13607 format = 'htmlEncode';
13609 if (format == 'raw' ) {
13613 if(name.substr(0, 6) == 'domtpl'){
13614 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
13617 // build an array of options to determine if value is undefined..
13619 // basically get 'xxxx.yyyy' then do
13620 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
13621 // (function () { Roo.log("Property not found"); return ''; })() :
13626 Roo.each(name.split('.'), function(st) {
13627 lookfor += (lookfor.length ? '.': '') + st;
13628 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
13631 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
13634 if(format && useF){
13636 args = args ? ',' + args : "";
13638 if(format.substr(0, 5) != "this."){
13639 format = "fm." + format + '(';
13641 format = 'this.call("'+ format.substr(5) + '", ';
13645 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
13648 if (args && args.length) {
13649 // called with xxyx.yuu:(test,test)
13651 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
13653 // raw.. - :raw modifier..
13654 return "'"+ sep + udef_st + name + ")"+sep+"'";
13658 // branched to use + in gecko and [].join() in others
13660 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
13661 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
13664 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
13665 body.push(tpl.body.replace(/(\r\n|\n)/g,
13666 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
13667 body.push("'].join('');};};");
13668 body = body.join('');
13671 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
13673 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
13680 * same as applyTemplate, except it's done to one of the subTemplates
13681 * when using named templates, you can do:
13683 * var str = pl.applySubTemplate('your-name', values);
13686 * @param {Number} id of the template
13687 * @param {Object} values to apply to template
13688 * @param {Object} parent (normaly the instance of this object)
13690 applySubTemplate : function(id, values, parent)
13694 var t = this.tpls[id];
13698 if(t.ifCall && !t.ifCall.call(this, values, parent)){
13699 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
13703 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
13710 if(t.execCall && t.execCall.call(this, values, parent)){
13714 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
13720 var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
13721 parent = t.target ? values : parent;
13722 if(t.forCall && vs instanceof Array){
13724 for(var i = 0, len = vs.length; i < len; i++){
13726 buf[buf.length] = t.compiled.call(this, vs[i], parent);
13728 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
13730 //Roo.log(t.compiled);
13734 return buf.join('');
13737 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
13742 return t.compiled.call(this, vs, parent);
13744 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
13746 //Roo.log(t.compiled);
13754 applyTemplate : function(values){
13755 return this.master.compiled.call(this, values, {});
13756 //var s = this.subs;
13759 apply : function(){
13760 return this.applyTemplate.apply(this, arguments);
13765 Roo.DomTemplate.from = function(el){
13766 el = Roo.getDom(el);
13767 return new Roo.Domtemplate(el.value || el.innerHTML);
13770 * Ext JS Library 1.1.1
13771 * Copyright(c) 2006-2007, Ext JS, LLC.
13773 * Originally Released Under LGPL - original licence link has changed is not relivant.
13776 * <script type="text/javascript">
13780 * @class Roo.util.DelayedTask
13781 * Provides a convenient method of performing setTimeout where a new
13782 * timeout cancels the old timeout. An example would be performing validation on a keypress.
13783 * You can use this class to buffer
13784 * the keypress events for a certain number of milliseconds, and perform only if they stop
13785 * for that amount of time.
13786 * @constructor The parameters to this constructor serve as defaults and are not required.
13787 * @param {Function} fn (optional) The default function to timeout
13788 * @param {Object} scope (optional) The default scope of that timeout
13789 * @param {Array} args (optional) The default Array of arguments
13791 Roo.util.DelayedTask = function(fn, scope, args){
13792 var id = null, d, t;
13794 var call = function(){
13795 var now = new Date().getTime();
13799 fn.apply(scope, args || []);
13803 * Cancels any pending timeout and queues a new one
13804 * @param {Number} delay The milliseconds to delay
13805 * @param {Function} newFn (optional) Overrides function passed to constructor
13806 * @param {Object} newScope (optional) Overrides scope passed to constructor
13807 * @param {Array} newArgs (optional) Overrides args passed to constructor
13809 this.delay = function(delay, newFn, newScope, newArgs){
13810 if(id && delay != d){
13814 t = new Date().getTime();
13816 scope = newScope || scope;
13817 args = newArgs || args;
13819 id = setInterval(call, d);
13824 * Cancel the last queued timeout
13826 this.cancel = function(){
13834 * Ext JS Library 1.1.1
13835 * Copyright(c) 2006-2007, Ext JS, LLC.
13837 * Originally Released Under LGPL - original licence link has changed is not relivant.
13840 * <script type="text/javascript">
13843 * @class Roo.util.TaskRunner
13844 * Manage background tasks - not sure why this is better that setInterval?
13849 Roo.util.TaskRunner = function(interval){
13850 interval = interval || 10;
13851 var tasks = [], removeQueue = [];
13853 var running = false;
13855 var stopThread = function(){
13861 var startThread = function(){
13864 id = setInterval(runTasks, interval);
13868 var removeTask = function(task){
13869 removeQueue.push(task);
13875 var runTasks = function(){
13876 if(removeQueue.length > 0){
13877 for(var i = 0, len = removeQueue.length; i < len; i++){
13878 tasks.remove(removeQueue[i]);
13881 if(tasks.length < 1){
13886 var now = new Date().getTime();
13887 for(var i = 0, len = tasks.length; i < len; ++i){
13889 var itime = now - t.taskRunTime;
13890 if(t.interval <= itime){
13891 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
13892 t.taskRunTime = now;
13893 if(rt === false || t.taskRunCount === t.repeat){
13898 if(t.duration && t.duration <= (now - t.taskStartTime)){
13905 * Queues a new task.
13906 * @param {Object} task
13908 * Task property : interval = how frequent to run.
13909 * Task object should implement
13911 * Task object may implement
13912 * function onStop()
13914 this.start = function(task){
13916 task.taskStartTime = new Date().getTime();
13917 task.taskRunTime = 0;
13918 task.taskRunCount = 0;
13924 * @param {Object} task
13926 this.stop = function(task){
13933 this.stopAll = function(){
13935 for(var i = 0, len = tasks.length; i < len; i++){
13936 if(tasks[i].onStop){
13945 Roo.TaskMgr = new Roo.util.TaskRunner();/*
13947 * Ext JS Library 1.1.1
13948 * Copyright(c) 2006-2007, Ext JS, LLC.
13950 * Originally Released Under LGPL - original licence link has changed is not relivant.
13953 * <script type="text/javascript">
13958 * @class Roo.util.MixedCollection
13959 * @extends Roo.util.Observable
13960 * A Collection class that maintains both numeric indexes and keys and exposes events.
13962 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
13963 * collection (defaults to false)
13964 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
13965 * and return the key value for that item. This is used when available to look up the key on items that
13966 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
13967 * equivalent to providing an implementation for the {@link #getKey} method.
13969 Roo.util.MixedCollection = function(allowFunctions, keyFn){
13977 * Fires when the collection is cleared.
13982 * Fires when an item is added to the collection.
13983 * @param {Number} index The index at which the item was added.
13984 * @param {Object} o The item added.
13985 * @param {String} key The key associated with the added item.
13990 * Fires when an item is replaced in the collection.
13991 * @param {String} key he key associated with the new added.
13992 * @param {Object} old The item being replaced.
13993 * @param {Object} new The new item.
13998 * Fires when an item is removed from the collection.
13999 * @param {Object} o The item being removed.
14000 * @param {String} key (optional) The key associated with the removed item.
14005 this.allowFunctions = allowFunctions === true;
14007 this.getKey = keyFn;
14009 Roo.util.MixedCollection.superclass.constructor.call(this);
14012 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
14013 allowFunctions : false,
14016 * Adds an item to the collection.
14017 * @param {String} key The key to associate with the item
14018 * @param {Object} o The item to add.
14019 * @return {Object} The item added.
14021 add : function(key, o){
14022 if(arguments.length == 1){
14024 key = this.getKey(o);
14026 if(typeof key == "undefined" || key === null){
14028 this.items.push(o);
14029 this.keys.push(null);
14031 var old = this.map[key];
14033 return this.replace(key, o);
14036 this.items.push(o);
14038 this.keys.push(key);
14040 this.fireEvent("add", this.length-1, o, key);
14045 * MixedCollection has a generic way to fetch keys if you implement getKey.
14048 var mc = new Roo.util.MixedCollection();
14049 mc.add(someEl.dom.id, someEl);
14050 mc.add(otherEl.dom.id, otherEl);
14054 var mc = new Roo.util.MixedCollection();
14055 mc.getKey = function(el){
14061 // or via the constructor
14062 var mc = new Roo.util.MixedCollection(false, function(el){
14068 * @param o {Object} The item for which to find the key.
14069 * @return {Object} The key for the passed item.
14071 getKey : function(o){
14076 * Replaces an item in the collection.
14077 * @param {String} key The key associated with the item to replace, or the item to replace.
14078 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
14079 * @return {Object} The new item.
14081 replace : function(key, o){
14082 if(arguments.length == 1){
14084 key = this.getKey(o);
14086 var old = this.item(key);
14087 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
14088 return this.add(key, o);
14090 var index = this.indexOfKey(key);
14091 this.items[index] = o;
14093 this.fireEvent("replace", key, old, o);
14098 * Adds all elements of an Array or an Object to the collection.
14099 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
14100 * an Array of values, each of which are added to the collection.
14102 addAll : function(objs){
14103 if(arguments.length > 1 || objs instanceof Array){
14104 var args = arguments.length > 1 ? arguments : objs;
14105 for(var i = 0, len = args.length; i < len; i++){
14109 for(var key in objs){
14110 if(this.allowFunctions || typeof objs[key] != "function"){
14111 this.add(key, objs[key]);
14118 * Executes the specified function once for every item in the collection, passing each
14119 * item as the first and only parameter. returning false from the function will stop the iteration.
14120 * @param {Function} fn The function to execute for each item.
14121 * @param {Object} scope (optional) The scope in which to execute the function.
14123 each : function(fn, scope){
14124 var items = [].concat(this.items); // each safe for removal
14125 for(var i = 0, len = items.length; i < len; i++){
14126 if(fn.call(scope || items[i], items[i], i, len) === false){
14133 * Executes the specified function once for every key in the collection, passing each
14134 * key, and its associated item as the first two parameters.
14135 * @param {Function} fn The function to execute for each item.
14136 * @param {Object} scope (optional) The scope in which to execute the function.
14138 eachKey : function(fn, scope){
14139 for(var i = 0, len = this.keys.length; i < len; i++){
14140 fn.call(scope || window, this.keys[i], this.items[i], i, len);
14145 * Returns the first item in the collection which elicits a true return value from the
14146 * passed selection function.
14147 * @param {Function} fn The selection function to execute for each item.
14148 * @param {Object} scope (optional) The scope in which to execute the function.
14149 * @return {Object} The first item in the collection which returned true from the selection function.
14151 find : function(fn, scope){
14152 for(var i = 0, len = this.items.length; i < len; i++){
14153 if(fn.call(scope || window, this.items[i], this.keys[i])){
14154 return this.items[i];
14161 * Inserts an item at the specified index in the collection.
14162 * @param {Number} index The index to insert the item at.
14163 * @param {String} key The key to associate with the new item, or the item itself.
14164 * @param {Object} o (optional) If the second parameter was a key, the new item.
14165 * @return {Object} The item inserted.
14167 insert : function(index, key, o){
14168 if(arguments.length == 2){
14170 key = this.getKey(o);
14172 if(index >= this.length){
14173 return this.add(key, o);
14176 this.items.splice(index, 0, o);
14177 if(typeof key != "undefined" && key != null){
14180 this.keys.splice(index, 0, key);
14181 this.fireEvent("add", index, o, key);
14186 * Removed an item from the collection.
14187 * @param {Object} o The item to remove.
14188 * @return {Object} The item removed.
14190 remove : function(o){
14191 return this.removeAt(this.indexOf(o));
14195 * Remove an item from a specified index in the collection.
14196 * @param {Number} index The index within the collection of the item to remove.
14198 removeAt : function(index){
14199 if(index < this.length && index >= 0){
14201 var o = this.items[index];
14202 this.items.splice(index, 1);
14203 var key = this.keys[index];
14204 if(typeof key != "undefined"){
14205 delete this.map[key];
14207 this.keys.splice(index, 1);
14208 this.fireEvent("remove", o, key);
14213 * Removed an item associated with the passed key fom the collection.
14214 * @param {String} key The key of the item to remove.
14216 removeKey : function(key){
14217 return this.removeAt(this.indexOfKey(key));
14221 * Returns the number of items in the collection.
14222 * @return {Number} the number of items in the collection.
14224 getCount : function(){
14225 return this.length;
14229 * Returns index within the collection of the passed Object.
14230 * @param {Object} o The item to find the index of.
14231 * @return {Number} index of the item.
14233 indexOf : function(o){
14234 if(!this.items.indexOf){
14235 for(var i = 0, len = this.items.length; i < len; i++){
14236 if(this.items[i] == o) {
14242 return this.items.indexOf(o);
14247 * Returns index within the collection of the passed key.
14248 * @param {String} key The key to find the index of.
14249 * @return {Number} index of the key.
14251 indexOfKey : function(key){
14252 if(!this.keys.indexOf){
14253 for(var i = 0, len = this.keys.length; i < len; i++){
14254 if(this.keys[i] == key) {
14260 return this.keys.indexOf(key);
14265 * Returns the item associated with the passed key OR index. Key has priority over index.
14266 * @param {String/Number} key The key or index of the item.
14267 * @return {Object} The item associated with the passed key.
14269 item : function(key){
14270 if (key === 'length') {
14273 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
14274 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
14278 * Returns the item at the specified index.
14279 * @param {Number} index The index of the item.
14282 itemAt : function(index){
14283 return this.items[index];
14287 * Returns the item associated with the passed key.
14288 * @param {String/Number} key The key of the item.
14289 * @return {Object} The item associated with the passed key.
14291 key : function(key){
14292 return this.map[key];
14296 * Returns true if the collection contains the passed Object as an item.
14297 * @param {Object} o The Object to look for in the collection.
14298 * @return {Boolean} True if the collection contains the Object as an item.
14300 contains : function(o){
14301 return this.indexOf(o) != -1;
14305 * Returns true if the collection contains the passed Object as a key.
14306 * @param {String} key The key to look for in the collection.
14307 * @return {Boolean} True if the collection contains the Object as a key.
14309 containsKey : function(key){
14310 return typeof this.map[key] != "undefined";
14314 * Removes all items from the collection.
14316 clear : function(){
14321 this.fireEvent("clear");
14325 * Returns the first item in the collection.
14326 * @return {Object} the first item in the collection..
14328 first : function(){
14329 return this.items[0];
14333 * Returns the last item in the collection.
14334 * @return {Object} the last item in the collection..
14337 return this.items[this.length-1];
14340 _sort : function(property, dir, fn){
14341 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
14342 fn = fn || function(a, b){
14345 var c = [], k = this.keys, items = this.items;
14346 for(var i = 0, len = items.length; i < len; i++){
14347 c[c.length] = {key: k[i], value: items[i], index: i};
14349 c.sort(function(a, b){
14350 var v = fn(a[property], b[property]) * dsc;
14352 v = (a.index < b.index ? -1 : 1);
14356 for(var i = 0, len = c.length; i < len; i++){
14357 items[i] = c[i].value;
14360 this.fireEvent("sort", this);
14364 * Sorts this collection with the passed comparison function
14365 * @param {String} direction (optional) "ASC" or "DESC"
14366 * @param {Function} fn (optional) comparison function
14368 sort : function(dir, fn){
14369 this._sort("value", dir, fn);
14373 * Sorts this collection by keys
14374 * @param {String} direction (optional) "ASC" or "DESC"
14375 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
14377 keySort : function(dir, fn){
14378 this._sort("key", dir, fn || function(a, b){
14379 return String(a).toUpperCase()-String(b).toUpperCase();
14384 * Returns a range of items in this collection
14385 * @param {Number} startIndex (optional) defaults to 0
14386 * @param {Number} endIndex (optional) default to the last item
14387 * @return {Array} An array of items
14389 getRange : function(start, end){
14390 var items = this.items;
14391 if(items.length < 1){
14394 start = start || 0;
14395 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
14398 for(var i = start; i <= end; i++) {
14399 r[r.length] = items[i];
14402 for(var i = start; i >= end; i--) {
14403 r[r.length] = items[i];
14410 * Filter the <i>objects</i> in this collection by a specific property.
14411 * Returns a new collection that has been filtered.
14412 * @param {String} property A property on your objects
14413 * @param {String/RegExp} value Either string that the property values
14414 * should start with or a RegExp to test against the property
14415 * @return {MixedCollection} The new filtered collection
14417 filter : function(property, value){
14418 if(!value.exec){ // not a regex
14419 value = String(value);
14420 if(value.length == 0){
14421 return this.clone();
14423 value = new RegExp("^" + Roo.escapeRe(value), "i");
14425 return this.filterBy(function(o){
14426 return o && value.test(o[property]);
14431 * Filter by a function. * Returns a new collection that has been filtered.
14432 * The passed function will be called with each
14433 * object in the collection. If the function returns true, the value is included
14434 * otherwise it is filtered.
14435 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
14436 * @param {Object} scope (optional) The scope of the function (defaults to this)
14437 * @return {MixedCollection} The new filtered collection
14439 filterBy : function(fn, scope){
14440 var r = new Roo.util.MixedCollection();
14441 r.getKey = this.getKey;
14442 var k = this.keys, it = this.items;
14443 for(var i = 0, len = it.length; i < len; i++){
14444 if(fn.call(scope||this, it[i], k[i])){
14445 r.add(k[i], it[i]);
14452 * Creates a duplicate of this collection
14453 * @return {MixedCollection}
14455 clone : function(){
14456 var r = new Roo.util.MixedCollection();
14457 var k = this.keys, it = this.items;
14458 for(var i = 0, len = it.length; i < len; i++){
14459 r.add(k[i], it[i]);
14461 r.getKey = this.getKey;
14466 * Returns the item associated with the passed key or index.
14468 * @param {String/Number} key The key or index of the item.
14469 * @return {Object} The item associated with the passed key.
14471 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
14473 * Ext JS Library 1.1.1
14474 * Copyright(c) 2006-2007, Ext JS, LLC.
14476 * Originally Released Under LGPL - original licence link has changed is not relivant.
14479 * <script type="text/javascript">
14482 * @class Roo.util.JSON
14483 * Modified version of Douglas Crockford"s json.js that doesn"t
14484 * mess with the Object prototype
14485 * http://www.json.org/js.html
14488 Roo.util.JSON = new (function(){
14489 var useHasOwn = {}.hasOwnProperty ? true : false;
14491 // crashes Safari in some instances
14492 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
14494 var pad = function(n) {
14495 return n < 10 ? "0" + n : n;
14508 var encodeString = function(s){
14509 if (/["\\\x00-\x1f]/.test(s)) {
14510 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
14515 c = b.charCodeAt();
14517 Math.floor(c / 16).toString(16) +
14518 (c % 16).toString(16);
14521 return '"' + s + '"';
14524 var encodeArray = function(o){
14525 var a = ["["], b, i, l = o.length, v;
14526 for (i = 0; i < l; i += 1) {
14528 switch (typeof v) {
14537 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
14545 var encodeDate = function(o){
14546 return '"' + o.getFullYear() + "-" +
14547 pad(o.getMonth() + 1) + "-" +
14548 pad(o.getDate()) + "T" +
14549 pad(o.getHours()) + ":" +
14550 pad(o.getMinutes()) + ":" +
14551 pad(o.getSeconds()) + '"';
14555 * Encodes an Object, Array or other value
14556 * @param {Mixed} o The variable to encode
14557 * @return {String} The JSON string
14559 this.encode = function(o)
14561 // should this be extended to fully wrap stringify..
14563 if(typeof o == "undefined" || o === null){
14565 }else if(o instanceof Array){
14566 return encodeArray(o);
14567 }else if(o instanceof Date){
14568 return encodeDate(o);
14569 }else if(typeof o == "string"){
14570 return encodeString(o);
14571 }else if(typeof o == "number"){
14572 return isFinite(o) ? String(o) : "null";
14573 }else if(typeof o == "boolean"){
14576 var a = ["{"], b, i, v;
14578 if(!useHasOwn || o.hasOwnProperty(i)) {
14580 switch (typeof v) {
14589 a.push(this.encode(i), ":",
14590 v === null ? "null" : this.encode(v));
14601 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
14602 * @param {String} json The JSON string
14603 * @return {Object} The resulting object
14605 this.decode = function(json){
14607 return /** eval:var:json */ eval("(" + json + ')');
14611 * Shorthand for {@link Roo.util.JSON#encode}
14612 * @member Roo encode
14614 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
14616 * Shorthand for {@link Roo.util.JSON#decode}
14617 * @member Roo decode
14619 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
14622 * Ext JS Library 1.1.1
14623 * Copyright(c) 2006-2007, Ext JS, LLC.
14625 * Originally Released Under LGPL - original licence link has changed is not relivant.
14628 * <script type="text/javascript">
14632 * @class Roo.util.Format
14633 * Reusable data formatting functions
14636 Roo.util.Format = function(){
14637 var trimRe = /^\s+|\s+$/g;
14640 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
14641 * @param {String} value The string to truncate
14642 * @param {Number} length The maximum length to allow before truncating
14643 * @return {String} The converted text
14645 ellipsis : function(value, len){
14646 if(value && value.length > len){
14647 return value.substr(0, len-3)+"...";
14653 * Checks a reference and converts it to empty string if it is undefined
14654 * @param {Mixed} value Reference to check
14655 * @return {Mixed} Empty string if converted, otherwise the original value
14657 undef : function(value){
14658 return typeof value != "undefined" ? value : "";
14662 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
14663 * @param {String} value The string to encode
14664 * @return {String} The encoded text
14666 htmlEncode : function(value){
14667 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
14671 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
14672 * @param {String} value The string to decode
14673 * @return {String} The decoded text
14675 htmlDecode : function(value){
14676 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
14680 * Trims any whitespace from either side of a string
14681 * @param {String} value The text to trim
14682 * @return {String} The trimmed text
14684 trim : function(value){
14685 return String(value).replace(trimRe, "");
14689 * Returns a substring from within an original string
14690 * @param {String} value The original text
14691 * @param {Number} start The start index of the substring
14692 * @param {Number} length The length of the substring
14693 * @return {String} The substring
14695 substr : function(value, start, length){
14696 return String(value).substr(start, length);
14700 * Converts a string to all lower case letters
14701 * @param {String} value The text to convert
14702 * @return {String} The converted text
14704 lowercase : function(value){
14705 return String(value).toLowerCase();
14709 * Converts a string to all upper case letters
14710 * @param {String} value The text to convert
14711 * @return {String} The converted text
14713 uppercase : function(value){
14714 return String(value).toUpperCase();
14718 * Converts the first character only of a string to upper case
14719 * @param {String} value The text to convert
14720 * @return {String} The converted text
14722 capitalize : function(value){
14723 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
14727 call : function(value, fn){
14728 if(arguments.length > 2){
14729 var args = Array.prototype.slice.call(arguments, 2);
14730 args.unshift(value);
14732 return /** eval:var:value */ eval(fn).apply(window, args);
14734 /** eval:var:value */
14735 return /** eval:var:value */ eval(fn).call(window, value);
14741 * safer version of Math.toFixed..??/
14742 * @param {Number/String} value The numeric value to format
14743 * @param {Number/String} value Decimal places
14744 * @return {String} The formatted currency string
14746 toFixed : function(v, n)
14748 // why not use to fixed - precision is buggered???
14750 return Math.round(v-0);
14752 var fact = Math.pow(10,n+1);
14753 v = (Math.round((v-0)*fact))/fact;
14754 var z = (''+fact).substring(2);
14755 if (v == Math.floor(v)) {
14756 return Math.floor(v) + '.' + z;
14759 // now just padd decimals..
14760 var ps = String(v).split('.');
14761 var fd = (ps[1] + z);
14762 var r = fd.substring(0,n);
14763 var rm = fd.substring(n);
14765 return ps[0] + '.' + r;
14767 r*=1; // turn it into a number;
14769 if (String(r).length != n) {
14772 r = String(r).substring(1); // chop the end off.
14775 return ps[0] + '.' + r;
14780 * Format a number as US currency
14781 * @param {Number/String} value The numeric value to format
14782 * @return {String} The formatted currency string
14784 usMoney : function(v){
14785 return '$' + Roo.util.Format.number(v);
14790 * eventually this should probably emulate php's number_format
14791 * @param {Number/String} value The numeric value to format
14792 * @param {Number} decimals number of decimal places
14793 * @param {String} delimiter for thousands (default comma)
14794 * @return {String} The formatted currency string
14796 number : function(v, decimals, thousandsDelimiter)
14798 // multiply and round.
14799 decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
14800 thousandsDelimiter = typeof(thousandsDelimiter) == 'undefined' ? ',' : thousandsDelimiter;
14802 var mul = Math.pow(10, decimals);
14803 var zero = String(mul).substring(1);
14804 v = (Math.round((v-0)*mul))/mul;
14806 // if it's '0' number.. then
14808 //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
14810 var ps = v.split('.');
14813 var r = /(\d+)(\d{3})/;
14816 if(thousandsDelimiter.length != 0) {
14817 whole = whole.replace(/\B(?=(\d{3})+(?!\d))/g, thousandsDelimiter );
14822 (decimals ? ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
14823 // does not have decimals
14824 (decimals ? ('.' + zero) : '');
14827 return whole + sub ;
14831 * Parse a value into a formatted date using the specified format pattern.
14832 * @param {Mixed} value The value to format
14833 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
14834 * @return {String} The formatted date string
14836 date : function(v, format){
14840 if(!(v instanceof Date)){
14841 v = new Date(Date.parse(v));
14843 return v.dateFormat(format || Roo.util.Format.defaults.date);
14847 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
14848 * @param {String} format Any valid date format string
14849 * @return {Function} The date formatting function
14851 dateRenderer : function(format){
14852 return function(v){
14853 return Roo.util.Format.date(v, format);
14858 stripTagsRE : /<\/?[^>]+>/gi,
14861 * Strips all HTML tags
14862 * @param {Mixed} value The text from which to strip tags
14863 * @return {String} The stripped text
14865 stripTags : function(v){
14866 return !v ? v : String(v).replace(this.stripTagsRE, "");
14870 * Size in Mb,Gb etc.
14871 * @param {Number} value The number to be formated
14872 * @param {number} decimals how many decimal places
14873 * @return {String} the formated string
14875 size : function(value, decimals)
14877 var sizes = ['b', 'k', 'M', 'G', 'T'];
14881 var i = parseInt(Math.floor(Math.log(value) / Math.log(1024)));
14882 return Roo.util.Format.number(value/ Math.pow(1024, i) ,decimals) + sizes[i];
14889 Roo.util.Format.defaults = {
14893 * Ext JS Library 1.1.1
14894 * Copyright(c) 2006-2007, Ext JS, LLC.
14896 * Originally Released Under LGPL - original licence link has changed is not relivant.
14899 * <script type="text/javascript">
14906 * @class Roo.MasterTemplate
14907 * @extends Roo.Template
14908 * Provides a template that can have child templates. The syntax is:
14910 var t = new Roo.MasterTemplate(
14911 '<select name="{name}">',
14912 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
14915 t.add('options', {value: 'foo', text: 'bar'});
14916 // or you can add multiple child elements in one shot
14917 t.addAll('options', [
14918 {value: 'foo', text: 'bar'},
14919 {value: 'foo2', text: 'bar2'},
14920 {value: 'foo3', text: 'bar3'}
14922 // then append, applying the master template values
14923 t.append('my-form', {name: 'my-select'});
14925 * A name attribute for the child template is not required if you have only one child
14926 * template or you want to refer to them by index.
14928 Roo.MasterTemplate = function(){
14929 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
14930 this.originalHtml = this.html;
14932 var m, re = this.subTemplateRe;
14935 while(m = re.exec(this.html)){
14936 var name = m[1], content = m[2];
14941 tpl : new Roo.Template(content)
14944 st[name] = st[subIndex];
14946 st[subIndex].tpl.compile();
14947 st[subIndex].tpl.call = this.call.createDelegate(this);
14950 this.subCount = subIndex;
14953 Roo.extend(Roo.MasterTemplate, Roo.Template, {
14955 * The regular expression used to match sub templates
14959 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
14962 * Applies the passed values to a child template.
14963 * @param {String/Number} name (optional) The name or index of the child template
14964 * @param {Array/Object} values The values to be applied to the template
14965 * @return {MasterTemplate} this
14967 add : function(name, values){
14968 if(arguments.length == 1){
14969 values = arguments[0];
14972 var s = this.subs[name];
14973 s.buffer[s.buffer.length] = s.tpl.apply(values);
14978 * Applies all the passed values to a child template.
14979 * @param {String/Number} name (optional) The name or index of the child template
14980 * @param {Array} values The values to be applied to the template, this should be an array of objects.
14981 * @param {Boolean} reset (optional) True to reset the template first
14982 * @return {MasterTemplate} this
14984 fill : function(name, values, reset){
14986 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
14994 for(var i = 0, len = values.length; i < len; i++){
14995 this.add(name, values[i]);
15001 * Resets the template for reuse
15002 * @return {MasterTemplate} this
15004 reset : function(){
15006 for(var i = 0; i < this.subCount; i++){
15012 applyTemplate : function(values){
15014 var replaceIndex = -1;
15015 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
15016 return s[++replaceIndex].buffer.join("");
15018 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
15021 apply : function(){
15022 return this.applyTemplate.apply(this, arguments);
15025 compile : function(){return this;}
15029 * Alias for fill().
15032 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
15034 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
15035 * var tpl = Roo.MasterTemplate.from('element-id');
15036 * @param {String/HTMLElement} el
15037 * @param {Object} config
15040 Roo.MasterTemplate.from = function(el, config){
15041 el = Roo.getDom(el);
15042 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
15045 * Ext JS Library 1.1.1
15046 * Copyright(c) 2006-2007, Ext JS, LLC.
15048 * Originally Released Under LGPL - original licence link has changed is not relivant.
15051 * <script type="text/javascript">
15056 * @class Roo.util.CSS
15057 * Utility class for manipulating CSS rules
15061 Roo.util.CSS = function(){
15063 var doc = document;
15065 var camelRe = /(-[a-z])/gi;
15066 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
15070 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
15071 * tag and appended to the HEAD of the document.
15072 * @param {String|Object} cssText The text containing the css rules
15073 * @param {String} id An id to add to the stylesheet for later removal
15074 * @return {StyleSheet}
15076 createStyleSheet : function(cssText, id){
15078 var head = doc.getElementsByTagName("head")[0];
15079 var nrules = doc.createElement("style");
15080 nrules.setAttribute("type", "text/css");
15082 nrules.setAttribute("id", id);
15084 if (typeof(cssText) != 'string') {
15085 // support object maps..
15086 // not sure if this a good idea..
15087 // perhaps it should be merged with the general css handling
15088 // and handle js style props.
15089 var cssTextNew = [];
15090 for(var n in cssText) {
15092 for(var k in cssText[n]) {
15093 citems.push( k + ' : ' +cssText[n][k] + ';' );
15095 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
15098 cssText = cssTextNew.join("\n");
15104 head.appendChild(nrules);
15105 ss = nrules.styleSheet;
15106 ss.cssText = cssText;
15109 nrules.appendChild(doc.createTextNode(cssText));
15111 nrules.cssText = cssText;
15113 head.appendChild(nrules);
15114 ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
15116 this.cacheStyleSheet(ss);
15121 * Removes a style or link tag by id
15122 * @param {String} id The id of the tag
15124 removeStyleSheet : function(id){
15125 var existing = doc.getElementById(id);
15127 existing.parentNode.removeChild(existing);
15132 * Dynamically swaps an existing stylesheet reference for a new one
15133 * @param {String} id The id of an existing link tag to remove
15134 * @param {String} url The href of the new stylesheet to include
15136 swapStyleSheet : function(id, url){
15137 this.removeStyleSheet(id);
15138 var ss = doc.createElement("link");
15139 ss.setAttribute("rel", "stylesheet");
15140 ss.setAttribute("type", "text/css");
15141 ss.setAttribute("id", id);
15142 ss.setAttribute("href", url);
15143 doc.getElementsByTagName("head")[0].appendChild(ss);
15147 * Refresh the rule cache if you have dynamically added stylesheets
15148 * @return {Object} An object (hash) of rules indexed by selector
15150 refreshCache : function(){
15151 return this.getRules(true);
15155 cacheStyleSheet : function(stylesheet){
15159 try{// try catch for cross domain access issue
15160 var ssRules = stylesheet.cssRules || stylesheet.rules;
15161 for(var j = ssRules.length-1; j >= 0; --j){
15162 rules[ssRules[j].selectorText] = ssRules[j];
15168 * Gets all css rules for the document
15169 * @param {Boolean} refreshCache true to refresh the internal cache
15170 * @return {Object} An object (hash) of rules indexed by selector
15172 getRules : function(refreshCache){
15173 if(rules == null || refreshCache){
15175 var ds = doc.styleSheets;
15176 for(var i =0, len = ds.length; i < len; i++){
15178 this.cacheStyleSheet(ds[i]);
15186 * Gets an an individual CSS rule by selector(s)
15187 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
15188 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
15189 * @return {CSSRule} The CSS rule or null if one is not found
15191 getRule : function(selector, refreshCache){
15192 var rs = this.getRules(refreshCache);
15193 if(!(selector instanceof Array)){
15194 return rs[selector];
15196 for(var i = 0; i < selector.length; i++){
15197 if(rs[selector[i]]){
15198 return rs[selector[i]];
15206 * Updates a rule property
15207 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
15208 * @param {String} property The css property
15209 * @param {String} value The new value for the property
15210 * @return {Boolean} true If a rule was found and updated
15212 updateRule : function(selector, property, value){
15213 if(!(selector instanceof Array)){
15214 var rule = this.getRule(selector);
15216 rule.style[property.replace(camelRe, camelFn)] = value;
15220 for(var i = 0; i < selector.length; i++){
15221 if(this.updateRule(selector[i], property, value)){
15231 * Ext JS Library 1.1.1
15232 * Copyright(c) 2006-2007, Ext JS, LLC.
15234 * Originally Released Under LGPL - original licence link has changed is not relivant.
15237 * <script type="text/javascript">
15243 * @class Roo.util.ClickRepeater
15244 * @extends Roo.util.Observable
15246 * A wrapper class which can be applied to any element. Fires a "click" event while the
15247 * mouse is pressed. The interval between firings may be specified in the config but
15248 * defaults to 10 milliseconds.
15250 * Optionally, a CSS class may be applied to the element during the time it is pressed.
15252 * @cfg {String/HTMLElement/Element} el The element to act as a button.
15253 * @cfg {Number} delay The initial delay before the repeating event begins firing.
15254 * Similar to an autorepeat key delay.
15255 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
15256 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
15257 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
15258 * "interval" and "delay" are ignored. "immediate" is honored.
15259 * @cfg {Boolean} preventDefault True to prevent the default click event
15260 * @cfg {Boolean} stopDefault True to stop the default click event
15263 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
15264 * 2007-02-02 jvs Renamed to ClickRepeater
15265 * 2007-02-03 jvs Modifications for FF Mac and Safari
15268 * @param {String/HTMLElement/Element} el The element to listen on
15269 * @param {Object} config
15271 Roo.util.ClickRepeater = function(el, config)
15273 this.el = Roo.get(el);
15274 this.el.unselectable();
15276 Roo.apply(this, config);
15281 * Fires when the mouse button is depressed.
15282 * @param {Roo.util.ClickRepeater} this
15284 "mousedown" : true,
15287 * Fires on a specified interval during the time the element is pressed.
15288 * @param {Roo.util.ClickRepeater} this
15293 * Fires when the mouse key is released.
15294 * @param {Roo.util.ClickRepeater} this
15299 this.el.on("mousedown", this.handleMouseDown, this);
15300 if(this.preventDefault || this.stopDefault){
15301 this.el.on("click", function(e){
15302 if(this.preventDefault){
15303 e.preventDefault();
15305 if(this.stopDefault){
15311 // allow inline handler
15313 this.on("click", this.handler, this.scope || this);
15316 Roo.util.ClickRepeater.superclass.constructor.call(this);
15319 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
15322 preventDefault : true,
15323 stopDefault : false,
15327 handleMouseDown : function(){
15328 clearTimeout(this.timer);
15330 if(this.pressClass){
15331 this.el.addClass(this.pressClass);
15333 this.mousedownTime = new Date();
15335 Roo.get(document).on("mouseup", this.handleMouseUp, this);
15336 this.el.on("mouseout", this.handleMouseOut, this);
15338 this.fireEvent("mousedown", this);
15339 this.fireEvent("click", this);
15341 this.timer = this.click.defer(this.delay || this.interval, this);
15345 click : function(){
15346 this.fireEvent("click", this);
15347 this.timer = this.click.defer(this.getInterval(), this);
15351 getInterval: function(){
15352 if(!this.accelerate){
15353 return this.interval;
15355 var pressTime = this.mousedownTime.getElapsed();
15356 if(pressTime < 500){
15358 }else if(pressTime < 1700){
15360 }else if(pressTime < 2600){
15362 }else if(pressTime < 3500){
15364 }else if(pressTime < 4400){
15366 }else if(pressTime < 5300){
15368 }else if(pressTime < 6200){
15376 handleMouseOut : function(){
15377 clearTimeout(this.timer);
15378 if(this.pressClass){
15379 this.el.removeClass(this.pressClass);
15381 this.el.on("mouseover", this.handleMouseReturn, this);
15385 handleMouseReturn : function(){
15386 this.el.un("mouseover", this.handleMouseReturn);
15387 if(this.pressClass){
15388 this.el.addClass(this.pressClass);
15394 handleMouseUp : function(){
15395 clearTimeout(this.timer);
15396 this.el.un("mouseover", this.handleMouseReturn);
15397 this.el.un("mouseout", this.handleMouseOut);
15398 Roo.get(document).un("mouseup", this.handleMouseUp);
15399 this.el.removeClass(this.pressClass);
15400 this.fireEvent("mouseup", this);
15403 * @class Roo.util.Clipboard
15409 Roo.util.Clipboard = {
15411 * Writes a string to the clipboard - using the Clipboard API if https, otherwise using text area.
15412 * @param {String} text to copy to clipboard
15414 write : function(text) {
15415 // navigator clipboard api needs a secure context (https)
15416 if (navigator.clipboard && window.isSecureContext) {
15417 // navigator clipboard api method'
15418 navigator.clipboard.writeText(text);
15421 // text area method
15422 var ta = document.createElement("textarea");
15424 // make the textarea out of viewport
15425 ta.style.position = "fixed";
15426 ta.style.left = "-999999px";
15427 ta.style.top = "-999999px";
15428 document.body.appendChild(ta);
15431 document.execCommand('copy');
15441 * Ext JS Library 1.1.1
15442 * Copyright(c) 2006-2007, Ext JS, LLC.
15444 * Originally Released Under LGPL - original licence link has changed is not relivant.
15447 * <script type="text/javascript">
15452 * @class Roo.KeyNav
15453 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
15454 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
15455 * way to implement custom navigation schemes for any UI component.</p>
15456 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
15457 * pageUp, pageDown, del, home, end. Usage:</p>
15459 var nav = new Roo.KeyNav("my-element", {
15460 "left" : function(e){
15461 this.moveLeft(e.ctrlKey);
15463 "right" : function(e){
15464 this.moveRight(e.ctrlKey);
15466 "enter" : function(e){
15473 * @param {String/HTMLElement/Roo.Element} el The element to bind to
15474 * @param {Object} config The config
15476 Roo.KeyNav = function(el, config){
15477 this.el = Roo.get(el);
15478 Roo.apply(this, config);
15479 if(!this.disabled){
15480 this.disabled = true;
15485 Roo.KeyNav.prototype = {
15487 * @cfg {Boolean} disabled
15488 * True to disable this KeyNav instance (defaults to false)
15492 * @cfg {String} defaultEventAction
15493 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
15494 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
15495 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
15497 defaultEventAction: "stopEvent",
15499 * @cfg {Boolean} forceKeyDown
15500 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
15501 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
15502 * handle keydown instead of keypress.
15504 forceKeyDown : false,
15507 prepareEvent : function(e){
15508 var k = e.getKey();
15509 var h = this.keyToHandler[k];
15510 //if(h && this[h]){
15511 // e.stopPropagation();
15513 if(Roo.isSafari && h && k >= 37 && k <= 40){
15519 relay : function(e){
15520 var k = e.getKey();
15521 var h = this.keyToHandler[k];
15523 if(this.doRelay(e, this[h], h) !== true){
15524 e[this.defaultEventAction]();
15530 doRelay : function(e, h, hname){
15531 return h.call(this.scope || this, e);
15534 // possible handlers
15548 // quick lookup hash
15565 * Enable this KeyNav
15567 enable: function(){
15569 // ie won't do special keys on keypress, no one else will repeat keys with keydown
15570 // the EventObject will normalize Safari automatically
15571 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
15572 this.el.on("keydown", this.relay, this);
15574 this.el.on("keydown", this.prepareEvent, this);
15575 this.el.on("keypress", this.relay, this);
15577 this.disabled = false;
15582 * Disable this KeyNav
15584 disable: function(){
15585 if(!this.disabled){
15586 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
15587 this.el.un("keydown", this.relay);
15589 this.el.un("keydown", this.prepareEvent);
15590 this.el.un("keypress", this.relay);
15592 this.disabled = true;
15597 * Ext JS Library 1.1.1
15598 * Copyright(c) 2006-2007, Ext JS, LLC.
15600 * Originally Released Under LGPL - original licence link has changed is not relivant.
15603 * <script type="text/javascript">
15608 * @class Roo.KeyMap
15609 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
15610 * The constructor accepts the same config object as defined by {@link #addBinding}.
15611 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
15612 * combination it will call the function with this signature (if the match is a multi-key
15613 * combination the callback will still be called only once): (String key, Roo.EventObject e)
15614 * A KeyMap can also handle a string representation of keys.<br />
15617 // map one key by key code
15618 var map = new Roo.KeyMap("my-element", {
15619 key: 13, // or Roo.EventObject.ENTER
15624 // map multiple keys to one action by string
15625 var map = new Roo.KeyMap("my-element", {
15631 // map multiple keys to multiple actions by strings and array of codes
15632 var map = new Roo.KeyMap("my-element", [
15635 fn: function(){ alert("Return was pressed"); }
15638 fn: function(){ alert('a, b or c was pressed'); }
15643 fn: function(){ alert('Control + shift + tab was pressed.'); }
15647 * <b>Note: A KeyMap starts enabled</b>
15649 * @param {String/HTMLElement/Roo.Element} el The element to bind to
15650 * @param {Object} config The config (see {@link #addBinding})
15651 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
15653 Roo.KeyMap = function(el, config, eventName){
15654 this.el = Roo.get(el);
15655 this.eventName = eventName || "keydown";
15656 this.bindings = [];
15658 this.addBinding(config);
15663 Roo.KeyMap.prototype = {
15665 * True to stop the event from bubbling and prevent the default browser action if the
15666 * key was handled by the KeyMap (defaults to false)
15672 * Add a new binding to this KeyMap. The following config object properties are supported:
15674 Property Type Description
15675 ---------- --------------- ----------------------------------------------------------------------
15676 key String/Array A single keycode or an array of keycodes to handle
15677 shift Boolean True to handle key only when shift is pressed (defaults to false)
15678 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
15679 alt Boolean True to handle key only when alt is pressed (defaults to false)
15680 fn Function The function to call when KeyMap finds the expected key combination
15681 scope Object The scope of the callback function
15687 var map = new Roo.KeyMap(document, {
15688 key: Roo.EventObject.ENTER,
15693 //Add a new binding to the existing KeyMap later
15701 * @param {Object/Array} config A single KeyMap config or an array of configs
15703 addBinding : function(config){
15704 if(config instanceof Array){
15705 for(var i = 0, len = config.length; i < len; i++){
15706 this.addBinding(config[i]);
15710 var keyCode = config.key,
15711 shift = config.shift,
15712 ctrl = config.ctrl,
15715 scope = config.scope;
15716 if(typeof keyCode == "string"){
15718 var keyString = keyCode.toUpperCase();
15719 for(var j = 0, len = keyString.length; j < len; j++){
15720 ks.push(keyString.charCodeAt(j));
15724 var keyArray = keyCode instanceof Array;
15725 var handler = function(e){
15726 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
15727 var k = e.getKey();
15729 for(var i = 0, len = keyCode.length; i < len; i++){
15730 if(keyCode[i] == k){
15731 if(this.stopEvent){
15734 fn.call(scope || window, k, e);
15740 if(this.stopEvent){
15743 fn.call(scope || window, k, e);
15748 this.bindings.push(handler);
15752 * Shorthand for adding a single key listener
15753 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
15754 * following options:
15755 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
15756 * @param {Function} fn The function to call
15757 * @param {Object} scope (optional) The scope of the function
15759 on : function(key, fn, scope){
15760 var keyCode, shift, ctrl, alt;
15761 if(typeof key == "object" && !(key instanceof Array)){
15780 handleKeyDown : function(e){
15781 if(this.enabled){ //just in case
15782 var b = this.bindings;
15783 for(var i = 0, len = b.length; i < len; i++){
15784 b[i].call(this, e);
15790 * Returns true if this KeyMap is enabled
15791 * @return {Boolean}
15793 isEnabled : function(){
15794 return this.enabled;
15798 * Enables this KeyMap
15800 enable: function(){
15802 this.el.on(this.eventName, this.handleKeyDown, this);
15803 this.enabled = true;
15808 * Disable this KeyMap
15810 disable: function(){
15812 this.el.removeListener(this.eventName, this.handleKeyDown, this);
15813 this.enabled = false;
15818 * Ext JS Library 1.1.1
15819 * Copyright(c) 2006-2007, Ext JS, LLC.
15821 * Originally Released Under LGPL - original licence link has changed is not relivant.
15824 * <script type="text/javascript">
15829 * @class Roo.util.TextMetrics
15830 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
15831 * wide, in pixels, a given block of text will be.
15834 Roo.util.TextMetrics = function(){
15838 * Measures the size of the specified text
15839 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
15840 * that can affect the size of the rendered text
15841 * @param {String} text The text to measure
15842 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
15843 * in order to accurately measure the text height
15844 * @return {Object} An object containing the text's size {width: (width), height: (height)}
15846 measure : function(el, text, fixedWidth){
15848 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
15851 shared.setFixedWidth(fixedWidth || 'auto');
15852 return shared.getSize(text);
15856 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
15857 * the overhead of multiple calls to initialize the style properties on each measurement.
15858 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
15859 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
15860 * in order to accurately measure the text height
15861 * @return {Roo.util.TextMetrics.Instance} instance The new instance
15863 createInstance : function(el, fixedWidth){
15864 return Roo.util.TextMetrics.Instance(el, fixedWidth);
15870 * @class Roo.util.TextMetrics.Instance
15871 * Instance of TextMetrics Calcuation
15873 * Create a new TextMetrics Instance
15874 * @param {Object} bindto
15875 * @param {Boolean} fixedWidth
15878 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth)
15880 var ml = new Roo.Element(document.createElement('div'));
15881 document.body.appendChild(ml.dom);
15882 ml.position('absolute');
15883 ml.setLeftTop(-1000, -1000);
15887 ml.setWidth(fixedWidth);
15892 * Returns the size of the specified text based on the internal element's style and width properties
15893 * @param {String} text The text to measure
15894 * @return {Object} An object containing the text's size {width: (width), height: (height)}
15896 getSize : function(text){
15898 var s = ml.getSize();
15904 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
15905 * that can affect the size of the rendered text
15906 * @param {String/HTMLElement} el The element, dom node or id
15908 bind : function(el){
15910 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
15915 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
15916 * to set a fixed width in order to accurately measure the text height.
15917 * @param {Number} width The width to set on the element
15919 setFixedWidth : function(width){
15920 ml.setWidth(width);
15924 * Returns the measured width of the specified text
15925 * @param {String} text The text to measure
15926 * @return {Number} width The width in pixels
15928 getWidth : function(text){
15929 ml.dom.style.width = 'auto';
15930 return this.getSize(text).width;
15934 * Returns the measured height of the specified text. For multiline text, be sure to call
15935 * {@link #setFixedWidth} if necessary.
15936 * @param {String} text The text to measure
15937 * @return {Number} height The height in pixels
15939 getHeight : function(text){
15940 return this.getSize(text).height;
15944 instance.bind(bindTo);
15949 // backwards compat
15950 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
15952 * Ext JS Library 1.1.1
15953 * Copyright(c) 2006-2007, Ext JS, LLC.
15955 * Originally Released Under LGPL - original licence link has changed is not relivant.
15958 * <script type="text/javascript">
15962 * @class Roo.state.Provider
15963 * Abstract base class for state provider implementations. This class provides methods
15964 * for encoding and decoding <b>typed</b> variables including dates and defines the
15965 * Provider interface.
15967 Roo.state.Provider = function(){
15969 * @event statechange
15970 * Fires when a state change occurs.
15971 * @param {Provider} this This state provider
15972 * @param {String} key The state key which was changed
15973 * @param {String} value The encoded value for the state
15976 "statechange": true
15979 Roo.state.Provider.superclass.constructor.call(this);
15981 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
15983 * Returns the current value for a key
15984 * @param {String} name The key name
15985 * @param {Mixed} defaultValue A default value to return if the key's value is not found
15986 * @return {Mixed} The state data
15988 get : function(name, defaultValue){
15989 return typeof this.state[name] == "undefined" ?
15990 defaultValue : this.state[name];
15994 * Clears a value from the state
15995 * @param {String} name The key name
15997 clear : function(name){
15998 delete this.state[name];
15999 this.fireEvent("statechange", this, name, null);
16003 * Sets the value for a key
16004 * @param {String} name The key name
16005 * @param {Mixed} value The value to set
16007 set : function(name, value){
16008 this.state[name] = value;
16009 this.fireEvent("statechange", this, name, value);
16013 * Decodes a string previously encoded with {@link #encodeValue}.
16014 * @param {String} value The value to decode
16015 * @return {Mixed} The decoded value
16017 decodeValue : function(cookie){
16018 var re = /^(a|n|d|b|s|o)\:(.*)$/;
16019 var matches = re.exec(unescape(cookie));
16020 if(!matches || !matches[1]) {
16021 return; // non state cookie
16023 var type = matches[1];
16024 var v = matches[2];
16027 return parseFloat(v);
16029 return new Date(Date.parse(v));
16034 var values = v.split("^");
16035 for(var i = 0, len = values.length; i < len; i++){
16036 all.push(this.decodeValue(values[i]));
16041 var values = v.split("^");
16042 for(var i = 0, len = values.length; i < len; i++){
16043 var kv = values[i].split("=");
16044 all[kv[0]] = this.decodeValue(kv[1]);
16053 * Encodes a value including type information. Decode with {@link #decodeValue}.
16054 * @param {Mixed} value The value to encode
16055 * @return {String} The encoded value
16057 encodeValue : function(v){
16059 if(typeof v == "number"){
16061 }else if(typeof v == "boolean"){
16062 enc = "b:" + (v ? "1" : "0");
16063 }else if(v instanceof Date){
16064 enc = "d:" + v.toGMTString();
16065 }else if(v instanceof Array){
16067 for(var i = 0, len = v.length; i < len; i++){
16068 flat += this.encodeValue(v[i]);
16074 }else if(typeof v == "object"){
16077 if(typeof v[key] != "function"){
16078 flat += key + "=" + this.encodeValue(v[key]) + "^";
16081 enc = "o:" + flat.substring(0, flat.length-1);
16085 return escape(enc);
16091 * Ext JS Library 1.1.1
16092 * Copyright(c) 2006-2007, Ext JS, LLC.
16094 * Originally Released Under LGPL - original licence link has changed is not relivant.
16097 * <script type="text/javascript">
16100 * @class Roo.state.Manager
16101 * This is the global state manager. By default all components that are "state aware" check this class
16102 * for state information if you don't pass them a custom state provider. In order for this class
16103 * to be useful, it must be initialized with a provider when your application initializes.
16105 // in your initialization function
16107 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
16109 // supposed you have a {@link Roo.BorderLayout}
16110 var layout = new Roo.BorderLayout(...);
16111 layout.restoreState();
16112 // or a {Roo.BasicDialog}
16113 var dialog = new Roo.BasicDialog(...);
16114 dialog.restoreState();
16118 Roo.state.Manager = function(){
16119 var provider = new Roo.state.Provider();
16123 * Configures the default state provider for your application
16124 * @param {Provider} stateProvider The state provider to set
16126 setProvider : function(stateProvider){
16127 provider = stateProvider;
16131 * Returns the current value for a key
16132 * @param {String} name The key name
16133 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
16134 * @return {Mixed} The state data
16136 get : function(key, defaultValue){
16137 return provider.get(key, defaultValue);
16141 * Sets the value for a key
16142 * @param {String} name The key name
16143 * @param {Mixed} value The state data
16145 set : function(key, value){
16146 provider.set(key, value);
16150 * Clears a value from the state
16151 * @param {String} name The key name
16153 clear : function(key){
16154 provider.clear(key);
16158 * Gets the currently configured state provider
16159 * @return {Provider} The state provider
16161 getProvider : function(){
16168 * Ext JS Library 1.1.1
16169 * Copyright(c) 2006-2007, Ext JS, LLC.
16171 * Originally Released Under LGPL - original licence link has changed is not relivant.
16174 * <script type="text/javascript">
16177 * @class Roo.state.CookieProvider
16178 * @extends Roo.state.Provider
16179 * The default Provider implementation which saves state via cookies.
16182 var cp = new Roo.state.CookieProvider({
16184 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
16185 domain: "roojs.com"
16187 Roo.state.Manager.setProvider(cp);
16189 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
16190 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
16191 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
16192 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
16193 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
16194 * domain the page is running on including the 'www' like 'www.roojs.com')
16195 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
16197 * Create a new CookieProvider
16198 * @param {Object} config The configuration object
16200 Roo.state.CookieProvider = function(config){
16201 Roo.state.CookieProvider.superclass.constructor.call(this);
16203 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
16204 this.domain = null;
16205 this.secure = false;
16206 Roo.apply(this, config);
16207 this.state = this.readCookies();
16210 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
16212 set : function(name, value){
16213 if(typeof value == "undefined" || value === null){
16217 this.setCookie(name, value);
16218 Roo.state.CookieProvider.superclass.set.call(this, name, value);
16222 clear : function(name){
16223 this.clearCookie(name);
16224 Roo.state.CookieProvider.superclass.clear.call(this, name);
16228 readCookies : function(){
16230 var c = document.cookie + ";";
16231 var re = /\s?(.*?)=(.*?);/g;
16233 while((matches = re.exec(c)) != null){
16234 var name = matches[1];
16235 var value = matches[2];
16236 if(name && name.substring(0,3) == "ys-"){
16237 cookies[name.substr(3)] = this.decodeValue(value);
16244 setCookie : function(name, value){
16245 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
16246 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
16247 ((this.path == null) ? "" : ("; path=" + this.path)) +
16248 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
16249 ((this.secure == true) ? "; secure" : "");
16253 clearCookie : function(name){
16254 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
16255 ((this.path == null) ? "" : ("; path=" + this.path)) +
16256 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
16257 ((this.secure == true) ? "; secure" : "");
16261 * Ext JS Library 1.1.1
16262 * Copyright(c) 2006-2007, Ext JS, LLC.
16264 * Originally Released Under LGPL - original licence link has changed is not relivant.
16267 * <script type="text/javascript">
16272 * @class Roo.ComponentMgr
16273 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
16276 Roo.ComponentMgr = function(){
16277 var all = new Roo.util.MixedCollection();
16281 * Registers a component.
16282 * @param {Roo.Component} c The component
16284 register : function(c){
16289 * Unregisters a component.
16290 * @param {Roo.Component} c The component
16292 unregister : function(c){
16297 * Returns a component by id
16298 * @param {String} id The component id
16300 get : function(id){
16301 return all.get(id);
16305 * Registers a function that will be called when a specified component is added to ComponentMgr
16306 * @param {String} id The component id
16307 * @param {Funtction} fn The callback function
16308 * @param {Object} scope The scope of the callback
16310 onAvailable : function(id, fn, scope){
16311 all.on("add", function(index, o){
16313 fn.call(scope || o, o);
16314 all.un("add", fn, scope);
16321 * Ext JS Library 1.1.1
16322 * Copyright(c) 2006-2007, Ext JS, LLC.
16324 * Originally Released Under LGPL - original licence link has changed is not relivant.
16327 * <script type="text/javascript">
16331 * @class Roo.Component
16332 * @extends Roo.util.Observable
16333 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
16334 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
16335 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
16336 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
16337 * All visual components (widgets) that require rendering into a layout should subclass Component.
16339 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
16340 * 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
16341 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
16343 Roo.Component = function(config){
16344 config = config || {};
16345 if(config.tagName || config.dom || typeof config == "string"){ // element object
16346 config = {el: config, id: config.id || config};
16348 this.initialConfig = config;
16350 Roo.apply(this, config);
16354 * Fires after the component is disabled.
16355 * @param {Roo.Component} this
16360 * Fires after the component is enabled.
16361 * @param {Roo.Component} this
16365 * @event beforeshow
16366 * Fires before the component is shown. Return false to stop the show.
16367 * @param {Roo.Component} this
16372 * Fires after the component is shown.
16373 * @param {Roo.Component} this
16377 * @event beforehide
16378 * Fires before the component is hidden. Return false to stop the hide.
16379 * @param {Roo.Component} this
16384 * Fires after the component is hidden.
16385 * @param {Roo.Component} this
16389 * @event beforerender
16390 * Fires before the component is rendered. Return false to stop the render.
16391 * @param {Roo.Component} this
16393 beforerender : true,
16396 * Fires after the component is rendered.
16397 * @param {Roo.Component} this
16401 * @event beforedestroy
16402 * Fires before the component is destroyed. Return false to stop the destroy.
16403 * @param {Roo.Component} this
16405 beforedestroy : true,
16408 * Fires after the component is destroyed.
16409 * @param {Roo.Component} this
16414 this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
16416 Roo.ComponentMgr.register(this);
16417 Roo.Component.superclass.constructor.call(this);
16418 this.initComponent();
16419 if(this.renderTo){ // not supported by all components yet. use at your own risk!
16420 this.render(this.renderTo);
16421 delete this.renderTo;
16426 Roo.Component.AUTO_ID = 1000;
16428 Roo.extend(Roo.Component, Roo.util.Observable, {
16430 * @scope Roo.Component.prototype
16432 * true if this component is hidden. Read-only.
16437 * true if this component is disabled. Read-only.
16442 * true if this component has been rendered. Read-only.
16446 /** @cfg {String} disableClass
16447 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
16449 disabledClass : "x-item-disabled",
16450 /** @cfg {Boolean} allowDomMove
16451 * Whether the component can move the Dom node when rendering (defaults to true).
16453 allowDomMove : true,
16454 /** @cfg {String} hideMode (display|visibility)
16455 * How this component should hidden. Supported values are
16456 * "visibility" (css visibility), "offsets" (negative offset position) and
16457 * "display" (css display) - defaults to "display".
16459 hideMode: 'display',
16462 ctype : "Roo.Component",
16465 * @cfg {String} actionMode
16466 * which property holds the element that used for hide() / show() / disable() / enable()
16467 * default is 'el' for forms you probably want to set this to fieldEl
16472 getActionEl : function(){
16473 return this[this.actionMode];
16476 initComponent : Roo.emptyFn,
16478 * If this is a lazy rendering component, render it to its container element.
16479 * @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.
16481 render : function(container, position){
16487 if(this.fireEvent("beforerender", this) === false){
16491 if(!container && this.el){
16492 this.el = Roo.get(this.el);
16493 container = this.el.dom.parentNode;
16494 this.allowDomMove = false;
16496 this.container = Roo.get(container);
16497 this.rendered = true;
16498 if(position !== undefined){
16499 if(typeof position == 'number'){
16500 position = this.container.dom.childNodes[position];
16502 position = Roo.getDom(position);
16505 this.onRender(this.container, position || null);
16507 this.el.addClass(this.cls);
16511 this.el.applyStyles(this.style);
16514 this.fireEvent("render", this);
16515 this.afterRender(this.container);
16528 // default function is not really useful
16529 onRender : function(ct, position){
16531 this.el = Roo.get(this.el);
16532 if(this.allowDomMove !== false){
16533 ct.dom.insertBefore(this.el.dom, position);
16539 getAutoCreate : function(){
16540 var cfg = typeof this.autoCreate == "object" ?
16541 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
16542 if(this.id && !cfg.id){
16549 afterRender : Roo.emptyFn,
16552 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
16553 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
16555 destroy : function(){
16556 if(this.fireEvent("beforedestroy", this) !== false){
16557 this.purgeListeners();
16558 this.beforeDestroy();
16560 this.el.removeAllListeners();
16562 if(this.actionMode == "container"){
16563 this.container.remove();
16567 Roo.ComponentMgr.unregister(this);
16568 this.fireEvent("destroy", this);
16573 beforeDestroy : function(){
16578 onDestroy : function(){
16583 * Returns the underlying {@link Roo.Element}.
16584 * @return {Roo.Element} The element
16586 getEl : function(){
16591 * Returns the id of this component.
16594 getId : function(){
16599 * Try to focus this component.
16600 * @param {Boolean} selectText True to also select the text in this component (if applicable)
16601 * @return {Roo.Component} this
16603 focus : function(selectText){
16606 if(selectText === true){
16607 this.el.dom.select();
16622 * Disable this component.
16623 * @return {Roo.Component} this
16625 disable : function(){
16629 this.disabled = true;
16630 this.fireEvent("disable", this);
16635 onDisable : function(){
16636 this.getActionEl().addClass(this.disabledClass);
16637 this.el.dom.disabled = true;
16641 * Enable this component.
16642 * @return {Roo.Component} this
16644 enable : function(){
16648 this.disabled = false;
16649 this.fireEvent("enable", this);
16654 onEnable : function(){
16655 this.getActionEl().removeClass(this.disabledClass);
16656 this.el.dom.disabled = false;
16660 * Convenience function for setting disabled/enabled by boolean.
16661 * @param {Boolean} disabled
16663 setDisabled : function(disabled){
16664 this[disabled ? "disable" : "enable"]();
16668 * Show this component.
16669 * @return {Roo.Component} this
16672 if(this.fireEvent("beforeshow", this) !== false){
16673 this.hidden = false;
16677 this.fireEvent("show", this);
16683 onShow : function(){
16684 var ae = this.getActionEl();
16685 if(this.hideMode == 'visibility'){
16686 ae.dom.style.visibility = "visible";
16687 }else if(this.hideMode == 'offsets'){
16688 ae.removeClass('x-hidden');
16690 ae.dom.style.display = "";
16695 * Hide this component.
16696 * @return {Roo.Component} this
16699 if(this.fireEvent("beforehide", this) !== false){
16700 this.hidden = true;
16704 this.fireEvent("hide", this);
16710 onHide : function(){
16711 var ae = this.getActionEl();
16712 if(this.hideMode == 'visibility'){
16713 ae.dom.style.visibility = "hidden";
16714 }else if(this.hideMode == 'offsets'){
16715 ae.addClass('x-hidden');
16717 ae.dom.style.display = "none";
16722 * Convenience function to hide or show this component by boolean.
16723 * @param {Boolean} visible True to show, false to hide
16724 * @return {Roo.Component} this
16726 setVisible: function(visible){
16736 * Returns true if this component is visible.
16738 isVisible : function(){
16739 return this.getActionEl().isVisible();
16742 cloneConfig : function(overrides){
16743 overrides = overrides || {};
16744 var id = overrides.id || Roo.id();
16745 var cfg = Roo.applyIf(overrides, this.initialConfig);
16746 cfg.id = id; // prevent dup id
16747 return new this.constructor(cfg);
16751 * Ext JS Library 1.1.1
16752 * Copyright(c) 2006-2007, Ext JS, LLC.
16754 * Originally Released Under LGPL - original licence link has changed is not relivant.
16757 * <script type="text/javascript">
16761 * @class Roo.BoxComponent
16762 * @extends Roo.Component
16763 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
16764 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
16765 * container classes should subclass BoxComponent so that they will work consistently when nested within other Roo
16766 * layout containers.
16768 * @param {Roo.Element/String/Object} config The configuration options.
16770 Roo.BoxComponent = function(config){
16771 Roo.Component.call(this, config);
16775 * Fires after the component is resized.
16776 * @param {Roo.Component} this
16777 * @param {Number} adjWidth The box-adjusted width that was set
16778 * @param {Number} adjHeight The box-adjusted height that was set
16779 * @param {Number} rawWidth The width that was originally specified
16780 * @param {Number} rawHeight The height that was originally specified
16785 * Fires after the component is moved.
16786 * @param {Roo.Component} this
16787 * @param {Number} x The new x position
16788 * @param {Number} y The new y position
16794 Roo.extend(Roo.BoxComponent, Roo.Component, {
16795 // private, set in afterRender to signify that the component has been rendered
16797 // private, used to defer height settings to subclasses
16798 deferHeight: false,
16799 /** @cfg {Number} width
16800 * width (optional) size of component
16802 /** @cfg {Number} height
16803 * height (optional) size of component
16807 * Sets the width and height of the component. This method fires the resize event. This method can accept
16808 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
16809 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
16810 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
16811 * @return {Roo.BoxComponent} this
16813 setSize : function(w, h){
16814 // support for standard size objects
16815 if(typeof w == 'object'){
16820 if(!this.boxReady){
16826 // prevent recalcs when not needed
16827 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
16830 this.lastSize = {width: w, height: h};
16832 var adj = this.adjustSize(w, h);
16833 var aw = adj.width, ah = adj.height;
16834 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
16835 var rz = this.getResizeEl();
16836 if(!this.deferHeight && aw !== undefined && ah !== undefined){
16837 rz.setSize(aw, ah);
16838 }else if(!this.deferHeight && ah !== undefined){
16840 }else if(aw !== undefined){
16843 this.onResize(aw, ah, w, h);
16844 this.fireEvent('resize', this, aw, ah, w, h);
16850 * Gets the current size of the component's underlying element.
16851 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
16853 getSize : function(){
16854 return this.el.getSize();
16858 * Gets the current XY position of the component's underlying element.
16859 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
16860 * @return {Array} The XY position of the element (e.g., [100, 200])
16862 getPosition : function(local){
16863 if(local === true){
16864 return [this.el.getLeft(true), this.el.getTop(true)];
16866 return this.xy || this.el.getXY();
16870 * Gets the current box measurements of the component's underlying element.
16871 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
16872 * @returns {Object} box An object in the format {x, y, width, height}
16874 getBox : function(local){
16875 var s = this.el.getSize();
16877 s.x = this.el.getLeft(true);
16878 s.y = this.el.getTop(true);
16880 var xy = this.xy || this.el.getXY();
16888 * Sets the current box measurements of the component's underlying element.
16889 * @param {Object} box An object in the format {x, y, width, height}
16890 * @returns {Roo.BoxComponent} this
16892 updateBox : function(box){
16893 this.setSize(box.width, box.height);
16894 this.setPagePosition(box.x, box.y);
16899 getResizeEl : function(){
16900 return this.resizeEl || this.el;
16904 getPositionEl : function(){
16905 return this.positionEl || this.el;
16909 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
16910 * This method fires the move event.
16911 * @param {Number} left The new left
16912 * @param {Number} top The new top
16913 * @returns {Roo.BoxComponent} this
16915 setPosition : function(x, y){
16918 if(!this.boxReady){
16921 var adj = this.adjustPosition(x, y);
16922 var ax = adj.x, ay = adj.y;
16924 var el = this.getPositionEl();
16925 if(ax !== undefined || ay !== undefined){
16926 if(ax !== undefined && ay !== undefined){
16927 el.setLeftTop(ax, ay);
16928 }else if(ax !== undefined){
16930 }else if(ay !== undefined){
16933 this.onPosition(ax, ay);
16934 this.fireEvent('move', this, ax, ay);
16940 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
16941 * This method fires the move event.
16942 * @param {Number} x The new x position
16943 * @param {Number} y The new y position
16944 * @returns {Roo.BoxComponent} this
16946 setPagePosition : function(x, y){
16949 if(!this.boxReady){
16952 if(x === undefined || y === undefined){ // cannot translate undefined points
16955 var p = this.el.translatePoints(x, y);
16956 this.setPosition(p.left, p.top);
16961 onRender : function(ct, position){
16962 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
16964 this.resizeEl = Roo.get(this.resizeEl);
16966 if(this.positionEl){
16967 this.positionEl = Roo.get(this.positionEl);
16972 afterRender : function(){
16973 Roo.BoxComponent.superclass.afterRender.call(this);
16974 this.boxReady = true;
16975 this.setSize(this.width, this.height);
16976 if(this.x || this.y){
16977 this.setPosition(this.x, this.y);
16979 if(this.pageX || this.pageY){
16980 this.setPagePosition(this.pageX, this.pageY);
16985 * Force the component's size to recalculate based on the underlying element's current height and width.
16986 * @returns {Roo.BoxComponent} this
16988 syncSize : function(){
16989 delete this.lastSize;
16990 this.setSize(this.el.getWidth(), this.el.getHeight());
16995 * Called after the component is resized, this method is empty by default but can be implemented by any
16996 * subclass that needs to perform custom logic after a resize occurs.
16997 * @param {Number} adjWidth The box-adjusted width that was set
16998 * @param {Number} adjHeight The box-adjusted height that was set
16999 * @param {Number} rawWidth The width that was originally specified
17000 * @param {Number} rawHeight The height that was originally specified
17002 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
17007 * Called after the component is moved, this method is empty by default but can be implemented by any
17008 * subclass that needs to perform custom logic after a move occurs.
17009 * @param {Number} x The new x position
17010 * @param {Number} y The new y position
17012 onPosition : function(x, y){
17017 adjustSize : function(w, h){
17018 if(this.autoWidth){
17021 if(this.autoHeight){
17024 return {width : w, height: h};
17028 adjustPosition : function(x, y){
17029 return {x : x, y: y};
17033 * Ext JS Library 1.1.1
17034 * Copyright(c) 2006-2007, Ext JS, LLC.
17036 * Originally Released Under LGPL - original licence link has changed is not relivant.
17039 * <script type="text/javascript">
17044 * @extends Roo.Element
17045 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
17046 * automatic maintaining of shadow/shim positions.
17047 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
17048 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
17049 * you can pass a string with a CSS class name. False turns off the shadow.
17050 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
17051 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
17052 * @cfg {String} cls CSS class to add to the element
17053 * @cfg {Number} zindex Starting z-index (defaults to 11000)
17054 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
17056 * @param {Object} config An object with config options.
17057 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
17060 Roo.Layer = function(config, existingEl){
17061 config = config || {};
17062 var dh = Roo.DomHelper;
17063 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
17065 this.dom = Roo.getDom(existingEl);
17068 var o = config.dh || {tag: "div", cls: "x-layer"};
17069 this.dom = dh.append(pel, o);
17072 this.addClass(config.cls);
17074 this.constrain = config.constrain !== false;
17075 this.visibilityMode = Roo.Element.VISIBILITY;
17077 this.id = this.dom.id = config.id;
17079 this.id = Roo.id(this.dom);
17081 this.zindex = config.zindex || this.getZIndex();
17082 this.position("absolute", this.zindex);
17084 this.shadowOffset = config.shadowOffset || 4;
17085 this.shadow = new Roo.Shadow({
17086 offset : this.shadowOffset,
17087 mode : config.shadow
17090 this.shadowOffset = 0;
17092 this.useShim = config.shim !== false && Roo.useShims;
17093 this.useDisplay = config.useDisplay;
17097 var supr = Roo.Element.prototype;
17099 // shims are shared among layer to keep from having 100 iframes
17102 Roo.extend(Roo.Layer, Roo.Element, {
17104 getZIndex : function(){
17105 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
17108 getShim : function(){
17115 var shim = shims.shift();
17117 shim = this.createShim();
17118 shim.enableDisplayMode('block');
17119 shim.dom.style.display = 'none';
17120 shim.dom.style.visibility = 'visible';
17122 var pn = this.dom.parentNode;
17123 if(shim.dom.parentNode != pn){
17124 pn.insertBefore(shim.dom, this.dom);
17126 shim.setStyle('z-index', this.getZIndex()-2);
17131 hideShim : function(){
17133 this.shim.setDisplayed(false);
17134 shims.push(this.shim);
17139 disableShadow : function(){
17141 this.shadowDisabled = true;
17142 this.shadow.hide();
17143 this.lastShadowOffset = this.shadowOffset;
17144 this.shadowOffset = 0;
17148 enableShadow : function(show){
17150 this.shadowDisabled = false;
17151 this.shadowOffset = this.lastShadowOffset;
17152 delete this.lastShadowOffset;
17160 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
17161 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
17162 sync : function(doShow){
17163 var sw = this.shadow;
17164 if(!this.updating && this.isVisible() && (sw || this.useShim)){
17165 var sh = this.getShim();
17167 var w = this.getWidth(),
17168 h = this.getHeight();
17170 var l = this.getLeft(true),
17171 t = this.getTop(true);
17173 if(sw && !this.shadowDisabled){
17174 if(doShow && !sw.isVisible()){
17177 sw.realign(l, t, w, h);
17183 // fit the shim behind the shadow, so it is shimmed too
17184 var a = sw.adjusts, s = sh.dom.style;
17185 s.left = (Math.min(l, l+a.l))+"px";
17186 s.top = (Math.min(t, t+a.t))+"px";
17187 s.width = (w+a.w)+"px";
17188 s.height = (h+a.h)+"px";
17195 sh.setLeftTop(l, t);
17202 destroy : function(){
17205 this.shadow.hide();
17207 this.removeAllListeners();
17208 var pn = this.dom.parentNode;
17210 pn.removeChild(this.dom);
17212 Roo.Element.uncache(this.id);
17215 remove : function(){
17220 beginUpdate : function(){
17221 this.updating = true;
17225 endUpdate : function(){
17226 this.updating = false;
17231 hideUnders : function(negOffset){
17233 this.shadow.hide();
17239 constrainXY : function(){
17240 if(this.constrain){
17241 var vw = Roo.lib.Dom.getViewWidth(),
17242 vh = Roo.lib.Dom.getViewHeight();
17243 var s = Roo.get(document).getScroll();
17245 var xy = this.getXY();
17246 var x = xy[0], y = xy[1];
17247 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
17248 // only move it if it needs it
17250 // first validate right/bottom
17251 if((x + w) > vw+s.left){
17252 x = vw - w - this.shadowOffset;
17255 if((y + h) > vh+s.top){
17256 y = vh - h - this.shadowOffset;
17259 // then make sure top/left isn't negative
17270 var ay = this.avoidY;
17271 if(y <= ay && (y+h) >= ay){
17277 supr.setXY.call(this, xy);
17283 isVisible : function(){
17284 return this.visible;
17288 showAction : function(){
17289 this.visible = true; // track visibility to prevent getStyle calls
17290 if(this.useDisplay === true){
17291 this.setDisplayed("");
17292 }else if(this.lastXY){
17293 supr.setXY.call(this, this.lastXY);
17294 }else if(this.lastLT){
17295 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
17300 hideAction : function(){
17301 this.visible = false;
17302 if(this.useDisplay === true){
17303 this.setDisplayed(false);
17305 this.setLeftTop(-10000,-10000);
17309 // overridden Element method
17310 setVisible : function(v, a, d, c, e){
17315 var cb = function(){
17320 }.createDelegate(this);
17321 supr.setVisible.call(this, true, true, d, cb, e);
17324 this.hideUnders(true);
17333 }.createDelegate(this);
17335 supr.setVisible.call(this, v, a, d, cb, e);
17344 storeXY : function(xy){
17345 delete this.lastLT;
17349 storeLeftTop : function(left, top){
17350 delete this.lastXY;
17351 this.lastLT = [left, top];
17355 beforeFx : function(){
17356 this.beforeAction();
17357 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
17361 afterFx : function(){
17362 Roo.Layer.superclass.afterFx.apply(this, arguments);
17363 this.sync(this.isVisible());
17367 beforeAction : function(){
17368 if(!this.updating && this.shadow){
17369 this.shadow.hide();
17373 // overridden Element method
17374 setLeft : function(left){
17375 this.storeLeftTop(left, this.getTop(true));
17376 supr.setLeft.apply(this, arguments);
17380 setTop : function(top){
17381 this.storeLeftTop(this.getLeft(true), top);
17382 supr.setTop.apply(this, arguments);
17386 setLeftTop : function(left, top){
17387 this.storeLeftTop(left, top);
17388 supr.setLeftTop.apply(this, arguments);
17392 setXY : function(xy, a, d, c, e){
17394 this.beforeAction();
17396 var cb = this.createCB(c);
17397 supr.setXY.call(this, xy, a, d, cb, e);
17404 createCB : function(c){
17415 // overridden Element method
17416 setX : function(x, a, d, c, e){
17417 this.setXY([x, this.getY()], a, d, c, e);
17420 // overridden Element method
17421 setY : function(y, a, d, c, e){
17422 this.setXY([this.getX(), y], a, d, c, e);
17425 // overridden Element method
17426 setSize : function(w, h, a, d, c, e){
17427 this.beforeAction();
17428 var cb = this.createCB(c);
17429 supr.setSize.call(this, w, h, a, d, cb, e);
17435 // overridden Element method
17436 setWidth : function(w, a, d, c, e){
17437 this.beforeAction();
17438 var cb = this.createCB(c);
17439 supr.setWidth.call(this, w, a, d, cb, e);
17445 // overridden Element method
17446 setHeight : function(h, a, d, c, e){
17447 this.beforeAction();
17448 var cb = this.createCB(c);
17449 supr.setHeight.call(this, h, a, d, cb, e);
17455 // overridden Element method
17456 setBounds : function(x, y, w, h, a, d, c, e){
17457 this.beforeAction();
17458 var cb = this.createCB(c);
17460 this.storeXY([x, y]);
17461 supr.setXY.call(this, [x, y]);
17462 supr.setSize.call(this, w, h, a, d, cb, e);
17465 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
17471 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
17472 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
17473 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
17474 * @param {Number} zindex The new z-index to set
17475 * @return {this} The Layer
17477 setZIndex : function(zindex){
17478 this.zindex = zindex;
17479 this.setStyle("z-index", zindex + 2);
17481 this.shadow.setZIndex(zindex + 1);
17484 this.shim.setStyle("z-index", zindex);
17489 * Original code for Roojs - LGPL
17490 * <script type="text/javascript">
17494 * @class Roo.XComponent
17495 * A delayed Element creator...
17496 * Or a way to group chunks of interface together.
17497 * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
17498 * used in conjunction with XComponent.build() it will create an instance of each element,
17499 * then call addxtype() to build the User interface.
17501 * Mypart.xyx = new Roo.XComponent({
17503 parent : 'Mypart.xyz', // empty == document.element.!!
17507 disabled : function() {}
17509 tree : function() { // return an tree of xtype declared components
17513 xtype : 'NestedLayoutPanel',
17520 * It can be used to build a big heiracy, with parent etc.
17521 * or you can just use this to render a single compoent to a dom element
17522 * MYPART.render(Roo.Element | String(id) | dom_element )
17529 * Roo is designed primarily as a single page application, so the UI build for a standard interface will
17530 * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
17532 * Each sub module is expected to have a parent pointing to the class name of it's parent module.
17534 * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
17535 * - if mulitple topModules exist, the last one is defined as the top module.
17539 * When the top level or multiple modules are to embedded into a existing HTML page,
17540 * the parent element can container '#id' of the element where the module will be drawn.
17544 * Unlike classic Roo, the bootstrap tends not to be used as a single page.
17545 * it relies more on a include mechanism, where sub modules are included into an outer page.
17546 * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
17548 * Bootstrap Roo Included elements
17550 * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
17551 * hence confusing the component builder as it thinks there are multiple top level elements.
17553 * String Over-ride & Translations
17555 * Our builder application writes all the strings as _strings and _named_strings. This is to enable the translation of elements,
17556 * and also the 'overlaying of string values - needed when different versions of the same application with different text content
17557 * are needed. @see Roo.XComponent.overlayString
17561 * @extends Roo.util.Observable
17563 * @param cfg {Object} configuration of component
17566 Roo.XComponent = function(cfg) {
17567 Roo.apply(this, cfg);
17571 * Fires when this the componnt is built
17572 * @param {Roo.XComponent} c the component
17577 this.region = this.region || 'center'; // default..
17578 Roo.XComponent.register(this);
17579 this.modules = false;
17580 this.el = false; // where the layout goes..
17584 Roo.extend(Roo.XComponent, Roo.util.Observable, {
17587 * The created element (with Roo.factory())
17588 * @type {Roo.Layout}
17594 * for BC - use el in new code
17595 * @type {Roo.Layout}
17601 * for BC - use el in new code
17602 * @type {Roo.Layout}
17607 * @cfg {Function|boolean} disabled
17608 * If this module is disabled by some rule, return true from the funtion
17613 * @cfg {String} parent
17614 * Name of parent element which it get xtype added to..
17619 * @cfg {String} order
17620 * Used to set the order in which elements are created (usefull for multiple tabs)
17625 * @cfg {String} name
17626 * String to display while loading.
17630 * @cfg {String} region
17631 * Region to render component to (defaults to center)
17636 * @cfg {Array} items
17637 * A single item array - the first element is the root of the tree..
17638 * It's done this way to stay compatible with the Xtype system...
17644 * The method that retuns the tree of parts that make up this compoennt
17651 * render element to dom or tree
17652 * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
17655 render : function(el)
17659 var hp = this.parent ? 1 : 0;
17660 Roo.debug && Roo.log(this);
17662 var tree = this._tree ? this._tree() : this.tree();
17665 if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
17666 // if parent is a '#.....' string, then let's use that..
17667 var ename = this.parent.substr(1);
17668 this.parent = false;
17669 Roo.debug && Roo.log(ename);
17671 case 'bootstrap-body':
17672 if (typeof(tree.el) != 'undefined' && tree.el == document.body) {
17673 // this is the BorderLayout standard?
17674 this.parent = { el : true };
17677 if (["Nest", "Content", "Grid", "Tree"].indexOf(tree.xtype) > -1) {
17678 // need to insert stuff...
17680 el : new Roo.bootstrap.layout.Border({
17681 el : document.body,
17687 tabPosition: 'top',
17688 //resizeTabs: true,
17689 alwaysShowTabs: true,
17699 if (typeof(Roo.bootstrap.Body) != 'undefined' ) {
17700 this.parent = { el : new Roo.bootstrap.Body() };
17701 Roo.debug && Roo.log("setting el to doc body");
17704 throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
17708 this.parent = { el : true};
17711 el = Roo.get(ename);
17712 if (typeof(Roo.bootstrap) != 'undefined' && tree['|xns'] == 'Roo.bootstrap') {
17713 this.parent = { el : true};
17720 if (!el && !this.parent) {
17721 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
17726 Roo.debug && Roo.log("EL:");
17727 Roo.debug && Roo.log(el);
17728 Roo.debug && Roo.log("this.parent.el:");
17729 Roo.debug && Roo.log(this.parent.el);
17732 // altertive root elements ??? - we need a better way to indicate these.
17733 var is_alt = Roo.XComponent.is_alt ||
17734 (typeof(tree.el) != 'undefined' && tree.el == document.body) ||
17735 (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
17736 (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
17740 if (!this.parent && is_alt) {
17741 //el = Roo.get(document.body);
17742 this.parent = { el : true };
17747 if (!this.parent) {
17749 Roo.debug && Roo.log("no parent - creating one");
17751 el = el ? Roo.get(el) : false;
17753 if (typeof(Roo.BorderLayout) == 'undefined' ) {
17756 el : new Roo.bootstrap.layout.Border({
17757 el: el || document.body,
17763 tabPosition: 'top',
17764 //resizeTabs: true,
17765 alwaysShowTabs: false,
17768 overflow: 'visible'
17774 // it's a top level one..
17776 el : new Roo.BorderLayout(el || document.body, {
17781 tabPosition: 'top',
17782 //resizeTabs: true,
17783 alwaysShowTabs: el && hp? false : true,
17784 hideTabs: el || !hp ? true : false,
17792 if (!this.parent.el) {
17793 // probably an old style ctor, which has been disabled.
17797 // The 'tree' method is '_tree now'
17799 tree.region = tree.region || this.region;
17800 var is_body = false;
17801 if (this.parent.el === true) {
17802 // bootstrap... - body..
17806 this.parent.el = Roo.factory(tree);
17810 this.el = this.parent.el.addxtype(tree, undefined, is_body);
17811 this.fireEvent('built', this);
17813 this.panel = this.el;
17814 this.layout = this.panel.layout;
17815 this.parentLayout = this.parent.layout || false;
17821 Roo.apply(Roo.XComponent, {
17823 * @property hideProgress
17824 * true to disable the building progress bar.. usefull on single page renders.
17827 hideProgress : false,
17829 * @property buildCompleted
17830 * True when the builder has completed building the interface.
17833 buildCompleted : false,
17836 * @property topModule
17837 * the upper most module - uses document.element as it's constructor.
17844 * @property modules
17845 * array of modules to be created by registration system.
17846 * @type {Array} of Roo.XComponent
17851 * @property elmodules
17852 * array of modules to be created by which use #ID
17853 * @type {Array} of Roo.XComponent
17860 * Is an alternative Root - normally used by bootstrap or other systems,
17861 * where the top element in the tree can wrap 'body'
17862 * @type {boolean} (default false)
17867 * @property build_from_html
17868 * Build elements from html - used by bootstrap HTML stuff
17869 * - this is cleared after build is completed
17870 * @type {boolean} (default false)
17873 build_from_html : false,
17875 * Register components to be built later.
17877 * This solves the following issues
17878 * - Building is not done on page load, but after an authentication process has occured.
17879 * - Interface elements are registered on page load
17880 * - Parent Interface elements may not be loaded before child, so this handles that..
17887 module : 'Pman.Tab.projectMgr',
17889 parent : 'Pman.layout',
17890 disabled : false, // or use a function..
17893 * * @param {Object} details about module
17895 register : function(obj) {
17897 Roo.XComponent.event.fireEvent('register', obj);
17898 switch(typeof(obj.disabled) ) {
17904 if ( obj.disabled() ) {
17910 if (obj.disabled || obj.region == '#disabled') {
17916 this.modules.push(obj);
17920 * convert a string to an object..
17921 * eg. 'AAA.BBB' -> finds AAA.BBB
17925 toObject : function(str)
17927 if (!str || typeof(str) == 'object') {
17930 if (str.substring(0,1) == '#') {
17934 var ar = str.split('.');
17939 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
17941 throw "Module not found : " + str;
17945 throw "Module not found : " + str;
17947 Roo.each(ar, function(e) {
17948 if (typeof(o[e]) == 'undefined') {
17949 throw "Module not found : " + str;
17960 * move modules into their correct place in the tree..
17963 preBuild : function ()
17966 Roo.each(this.modules , function (obj)
17968 Roo.XComponent.event.fireEvent('beforebuild', obj);
17970 var opar = obj.parent;
17972 obj.parent = this.toObject(opar);
17974 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
17979 Roo.debug && Roo.log("GOT top level module");
17980 Roo.debug && Roo.log(obj);
17981 obj.modules = new Roo.util.MixedCollection(false,
17982 function(o) { return o.order + '' }
17984 this.topModule = obj;
17987 // parent is a string (usually a dom element name..)
17988 if (typeof(obj.parent) == 'string') {
17989 this.elmodules.push(obj);
17992 if (obj.parent.constructor != Roo.XComponent) {
17993 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
17995 if (!obj.parent.modules) {
17996 obj.parent.modules = new Roo.util.MixedCollection(false,
17997 function(o) { return o.order + '' }
18000 if (obj.parent.disabled) {
18001 obj.disabled = true;
18003 obj.parent.modules.add(obj);
18008 * make a list of modules to build.
18009 * @return {Array} list of modules.
18012 buildOrder : function()
18015 var cmp = function(a,b) {
18016 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
18018 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
18019 throw "No top level modules to build";
18022 // make a flat list in order of modules to build.
18023 var mods = this.topModule ? [ this.topModule ] : [];
18026 // elmodules (is a list of DOM based modules )
18027 Roo.each(this.elmodules, function(e) {
18029 if (!this.topModule &&
18030 typeof(e.parent) == 'string' &&
18031 e.parent.substring(0,1) == '#' &&
18032 Roo.get(e.parent.substr(1))
18035 _this.topModule = e;
18041 // add modules to their parents..
18042 var addMod = function(m) {
18043 Roo.debug && Roo.log("build Order: add: " + m.name);
18046 if (m.modules && !m.disabled) {
18047 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
18048 m.modules.keySort('ASC', cmp );
18049 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
18051 m.modules.each(addMod);
18053 Roo.debug && Roo.log("build Order: no child modules");
18055 // not sure if this is used any more..
18057 m.finalize.name = m.name + " (clean up) ";
18058 mods.push(m.finalize);
18062 if (this.topModule && this.topModule.modules) {
18063 this.topModule.modules.keySort('ASC', cmp );
18064 this.topModule.modules.each(addMod);
18070 * Build the registered modules.
18071 * @param {Object} parent element.
18072 * @param {Function} optional method to call after module has been added.
18076 build : function(opts)
18079 if (typeof(opts) != 'undefined') {
18080 Roo.apply(this,opts);
18084 var mods = this.buildOrder();
18086 //this.allmods = mods;
18087 //Roo.debug && Roo.log(mods);
18089 if (!mods.length) { // should not happen
18090 throw "NO modules!!!";
18094 var msg = "Building Interface...";
18095 // flash it up as modal - so we store the mask!?
18096 if (!this.hideProgress && Roo.MessageBox) {
18097 Roo.MessageBox.show({ title: 'loading' });
18098 Roo.MessageBox.show({
18099 title: "Please wait...",
18109 var total = mods.length;
18112 var progressRun = function() {
18113 if (!mods.length) {
18114 Roo.debug && Roo.log('hide?');
18115 if (!this.hideProgress && Roo.MessageBox) {
18116 Roo.MessageBox.hide();
18118 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
18120 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
18126 var m = mods.shift();
18129 Roo.debug && Roo.log(m);
18130 // not sure if this is supported any more.. - modules that are are just function
18131 if (typeof(m) == 'function') {
18133 return progressRun.defer(10, _this);
18137 msg = "Building Interface " + (total - mods.length) +
18139 (m.name ? (' - ' + m.name) : '');
18140 Roo.debug && Roo.log(msg);
18141 if (!_this.hideProgress && Roo.MessageBox) {
18142 Roo.MessageBox.updateProgress( (total - mods.length)/total, msg );
18146 // is the module disabled?
18147 var disabled = (typeof(m.disabled) == 'function') ?
18148 m.disabled.call(m.module.disabled) : m.disabled;
18152 return progressRun(); // we do not update the display!
18160 // it's 10 on top level, and 1 on others??? why...
18161 return progressRun.defer(10, _this);
18164 progressRun.defer(1, _this);
18170 * Overlay a set of modified strings onto a component
18171 * This is dependant on our builder exporting the strings and 'named strings' elements.
18173 * @param {Object} element to overlay on - eg. Pman.Dialog.Login
18174 * @param {Object} associative array of 'named' string and it's new value.
18177 overlayStrings : function( component, strings )
18179 if (typeof(component['_named_strings']) == 'undefined') {
18180 throw "ERROR: component does not have _named_strings";
18182 for ( var k in strings ) {
18183 var md = typeof(component['_named_strings'][k]) == 'undefined' ? false : component['_named_strings'][k];
18184 if (md !== false) {
18185 component['_strings'][md] = strings[k];
18187 Roo.log('could not find named string: ' + k + ' in');
18188 Roo.log(component);
18203 * wrapper for event.on - aliased later..
18204 * Typically use to register a event handler for register:
18206 * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
18215 Roo.XComponent.event = new Roo.util.Observable({
18219 * Fires when an Component is registered,
18220 * set the disable property on the Component to stop registration.
18221 * @param {Roo.XComponent} c the component being registerd.
18226 * @event beforebuild
18227 * Fires before each Component is built
18228 * can be used to apply permissions.
18229 * @param {Roo.XComponent} c the component being registerd.
18232 'beforebuild' : true,
18234 * @event buildcomplete
18235 * Fires on the top level element when all elements have been built
18236 * @param {Roo.XComponent} the top level component.
18238 'buildcomplete' : true
18243 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event);
18246 * marked - a markdown parser
18247 * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
18248 * https://github.com/chjj/marked
18254 * Roo.Markdown - is a very crude wrapper around marked..
18258 * alert( Roo.Markdown.toHtml("Markdown *rocks*.") );
18260 * Note: move the sample code to the bottom of this
18261 * file before uncommenting it.
18266 Roo.Markdown.toHtml = function(text) {
18268 var c = new Roo.Markdown.marked.setOptions({
18269 renderer: new Roo.Markdown.marked.Renderer(),
18280 text = text.replace(/\\\n/g,' ');
18281 return Roo.Markdown.marked(text);
18286 // Wraps all "globals" so that the only thing
18287 // exposed is makeHtml().
18293 * eval:var:unescape
18301 var escape = function (html, encode) {
18303 .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&')
18304 .replace(/</g, '<')
18305 .replace(/>/g, '>')
18306 .replace(/"/g, '"')
18307 .replace(/'/g, ''');
18310 var unescape = function (html) {
18311 // explicitly match decimal, hex, and named HTML entities
18312 return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
18313 n = n.toLowerCase();
18314 if (n === 'colon') { return ':'; }
18315 if (n.charAt(0) === '#') {
18316 return n.charAt(1) === 'x'
18317 ? String.fromCharCode(parseInt(n.substring(2), 16))
18318 : String.fromCharCode(+n.substring(1));
18324 var replace = function (regex, opt) {
18325 regex = regex.source;
18327 return function self(name, val) {
18328 if (!name) { return new RegExp(regex, opt); }
18329 val = val.source || val;
18330 val = val.replace(/(^|[^\[])\^/g, '$1');
18331 regex = regex.replace(name, val);
18340 var noop = function () {}
18346 var merge = function (obj) {
18351 for (; i < arguments.length; i++) {
18352 target = arguments[i];
18353 for (key in target) {
18354 if (Object.prototype.hasOwnProperty.call(target, key)) {
18355 obj[key] = target[key];
18365 * Block-Level Grammar
18373 code: /^( {4}[^\n]+\n*)+/,
18375 hr: /^( *[-*_]){3,} *(?:\n+|$)/,
18376 heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
18378 lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
18379 blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
18380 list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
18381 html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
18382 def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
18384 paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
18388 block.bullet = /(?:[*+-]|\d+\.)/;
18389 block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
18390 block.item = replace(block.item, 'gm')
18391 (/bull/g, block.bullet)
18394 block.list = replace(block.list)
18395 (/bull/g, block.bullet)
18396 ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
18397 ('def', '\\n+(?=' + block.def.source + ')')
18400 block.blockquote = replace(block.blockquote)
18404 block._tag = '(?!(?:'
18405 + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
18406 + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
18407 + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
18409 block.html = replace(block.html)
18410 ('comment', /<!--[\s\S]*?-->/)
18411 ('closed', /<(tag)[\s\S]+?<\/\1>/)
18412 ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
18413 (/tag/g, block._tag)
18416 block.paragraph = replace(block.paragraph)
18418 ('heading', block.heading)
18419 ('lheading', block.lheading)
18420 ('blockquote', block.blockquote)
18421 ('tag', '<' + block._tag)
18426 * Normal Block Grammar
18429 block.normal = merge({}, block);
18432 * GFM Block Grammar
18435 block.gfm = merge({}, block.normal, {
18436 fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,
18438 heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
18441 block.gfm.paragraph = replace(block.paragraph)
18443 + block.gfm.fences.source.replace('\\1', '\\2') + '|'
18444 + block.list.source.replace('\\1', '\\3') + '|')
18448 * GFM + Tables Block Grammar
18451 block.tables = merge({}, block.gfm, {
18452 nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
18453 table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
18460 var Lexer = function (options) {
18462 this.tokens.links = {};
18463 this.options = options || marked.defaults;
18464 this.rules = block.normal;
18466 if (this.options.gfm) {
18467 if (this.options.tables) {
18468 this.rules = block.tables;
18470 this.rules = block.gfm;
18476 * Expose Block Rules
18479 Lexer.rules = block;
18482 * Static Lex Method
18485 Lexer.lex = function(src, options) {
18486 var lexer = new Lexer(options);
18487 return lexer.lex(src);
18494 Lexer.prototype.lex = function(src) {
18496 .replace(/\r\n|\r/g, '\n')
18497 .replace(/\t/g, ' ')
18498 .replace(/\u00a0/g, ' ')
18499 .replace(/\u2424/g, '\n');
18501 return this.token(src, true);
18508 Lexer.prototype.token = function(src, top, bq) {
18509 var src = src.replace(/^ +$/gm, '')
18522 if (cap = this.rules.newline.exec(src)) {
18523 src = src.substring(cap[0].length);
18524 if (cap[0].length > 1) {
18532 if (cap = this.rules.code.exec(src)) {
18533 src = src.substring(cap[0].length);
18534 cap = cap[0].replace(/^ {4}/gm, '');
18537 text: !this.options.pedantic
18538 ? cap.replace(/\n+$/, '')
18545 if (cap = this.rules.fences.exec(src)) {
18546 src = src.substring(cap[0].length);
18556 if (cap = this.rules.heading.exec(src)) {
18557 src = src.substring(cap[0].length);
18560 depth: cap[1].length,
18566 // table no leading pipe (gfm)
18567 if (top && (cap = this.rules.nptable.exec(src))) {
18568 src = src.substring(cap[0].length);
18572 header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
18573 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
18574 cells: cap[3].replace(/\n$/, '').split('\n')
18577 for (i = 0; i < item.align.length; i++) {
18578 if (/^ *-+: *$/.test(item.align[i])) {
18579 item.align[i] = 'right';
18580 } else if (/^ *:-+: *$/.test(item.align[i])) {
18581 item.align[i] = 'center';
18582 } else if (/^ *:-+ *$/.test(item.align[i])) {
18583 item.align[i] = 'left';
18585 item.align[i] = null;
18589 for (i = 0; i < item.cells.length; i++) {
18590 item.cells[i] = item.cells[i].split(/ *\| */);
18593 this.tokens.push(item);
18599 if (cap = this.rules.lheading.exec(src)) {
18600 src = src.substring(cap[0].length);
18603 depth: cap[2] === '=' ? 1 : 2,
18610 if (cap = this.rules.hr.exec(src)) {
18611 src = src.substring(cap[0].length);
18619 if (cap = this.rules.blockquote.exec(src)) {
18620 src = src.substring(cap[0].length);
18623 type: 'blockquote_start'
18626 cap = cap[0].replace(/^ *> ?/gm, '');
18628 // Pass `top` to keep the current
18629 // "toplevel" state. This is exactly
18630 // how markdown.pl works.
18631 this.token(cap, top, true);
18634 type: 'blockquote_end'
18641 if (cap = this.rules.list.exec(src)) {
18642 src = src.substring(cap[0].length);
18646 type: 'list_start',
18647 ordered: bull.length > 1
18650 // Get each top-level item.
18651 cap = cap[0].match(this.rules.item);
18657 for (; i < l; i++) {
18660 // Remove the list item's bullet
18661 // so it is seen as the next token.
18662 space = item.length;
18663 item = item.replace(/^ *([*+-]|\d+\.) +/, '');
18665 // Outdent whatever the
18666 // list item contains. Hacky.
18667 if (~item.indexOf('\n ')) {
18668 space -= item.length;
18669 item = !this.options.pedantic
18670 ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
18671 : item.replace(/^ {1,4}/gm, '');
18674 // Determine whether the next list item belongs here.
18675 // Backpedal if it does not belong in this list.
18676 if (this.options.smartLists && i !== l - 1) {
18677 b = block.bullet.exec(cap[i + 1])[0];
18678 if (bull !== b && !(bull.length > 1 && b.length > 1)) {
18679 src = cap.slice(i + 1).join('\n') + src;
18684 // Determine whether item is loose or not.
18685 // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
18686 // for discount behavior.
18687 loose = next || /\n\n(?!\s*$)/.test(item);
18689 next = item.charAt(item.length - 1) === '\n';
18690 if (!loose) { loose = next; }
18695 ? 'loose_item_start'
18696 : 'list_item_start'
18700 this.token(item, false, bq);
18703 type: 'list_item_end'
18715 if (cap = this.rules.html.exec(src)) {
18716 src = src.substring(cap[0].length);
18718 type: this.options.sanitize
18721 pre: !this.options.sanitizer
18722 && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
18729 if ((!bq && top) && (cap = this.rules.def.exec(src))) {
18730 src = src.substring(cap[0].length);
18731 this.tokens.links[cap[1].toLowerCase()] = {
18739 if (top && (cap = this.rules.table.exec(src))) {
18740 src = src.substring(cap[0].length);
18744 header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
18745 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
18746 cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
18749 for (i = 0; i < item.align.length; i++) {
18750 if (/^ *-+: *$/.test(item.align[i])) {
18751 item.align[i] = 'right';
18752 } else if (/^ *:-+: *$/.test(item.align[i])) {
18753 item.align[i] = 'center';
18754 } else if (/^ *:-+ *$/.test(item.align[i])) {
18755 item.align[i] = 'left';
18757 item.align[i] = null;
18761 for (i = 0; i < item.cells.length; i++) {
18762 item.cells[i] = item.cells[i]
18763 .replace(/^ *\| *| *\| *$/g, '')
18767 this.tokens.push(item);
18772 // top-level paragraph
18773 if (top && (cap = this.rules.paragraph.exec(src))) {
18774 src = src.substring(cap[0].length);
18777 text: cap[1].charAt(cap[1].length - 1) === '\n'
18778 ? cap[1].slice(0, -1)
18785 if (cap = this.rules.text.exec(src)) {
18786 // Top-level should never reach here.
18787 src = src.substring(cap[0].length);
18797 Error('Infinite loop on byte: ' + src.charCodeAt(0));
18801 return this.tokens;
18805 * Inline-Level Grammar
18809 escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
18810 autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
18812 tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
18813 link: /^!?\[(inside)\]\(href\)/,
18814 reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
18815 nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
18816 strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
18817 em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
18818 code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
18819 br: /^ {2,}\n(?!\s*$)/,
18821 text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
18824 inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
18825 inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
18827 inline.link = replace(inline.link)
18828 ('inside', inline._inside)
18829 ('href', inline._href)
18832 inline.reflink = replace(inline.reflink)
18833 ('inside', inline._inside)
18837 * Normal Inline Grammar
18840 inline.normal = merge({}, inline);
18843 * Pedantic Inline Grammar
18846 inline.pedantic = merge({}, inline.normal, {
18847 strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
18848 em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
18852 * GFM Inline Grammar
18855 inline.gfm = merge({}, inline.normal, {
18856 escape: replace(inline.escape)('])', '~|])')(),
18857 url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
18858 del: /^~~(?=\S)([\s\S]*?\S)~~/,
18859 text: replace(inline.text)
18861 ('|', '|https?://|')
18866 * GFM + Line Breaks Inline Grammar
18869 inline.breaks = merge({}, inline.gfm, {
18870 br: replace(inline.br)('{2,}', '*')(),
18871 text: replace(inline.gfm.text)('{2,}', '*')()
18875 * Inline Lexer & Compiler
18878 var InlineLexer = function (links, options) {
18879 this.options = options || marked.defaults;
18880 this.links = links;
18881 this.rules = inline.normal;
18882 this.renderer = this.options.renderer || new Renderer;
18883 this.renderer.options = this.options;
18887 Error('Tokens array requires a `links` property.');
18890 if (this.options.gfm) {
18891 if (this.options.breaks) {
18892 this.rules = inline.breaks;
18894 this.rules = inline.gfm;
18896 } else if (this.options.pedantic) {
18897 this.rules = inline.pedantic;
18902 * Expose Inline Rules
18905 InlineLexer.rules = inline;
18908 * Static Lexing/Compiling Method
18911 InlineLexer.output = function(src, links, options) {
18912 var inline = new InlineLexer(links, options);
18913 return inline.output(src);
18920 InlineLexer.prototype.output = function(src) {
18929 if (cap = this.rules.escape.exec(src)) {
18930 src = src.substring(cap[0].length);
18936 if (cap = this.rules.autolink.exec(src)) {
18937 src = src.substring(cap[0].length);
18938 if (cap[2] === '@') {
18939 text = cap[1].charAt(6) === ':'
18940 ? this.mangle(cap[1].substring(7))
18941 : this.mangle(cap[1]);
18942 href = this.mangle('mailto:') + text;
18944 text = escape(cap[1]);
18947 out += this.renderer.link(href, null, text);
18952 if (!this.inLink && (cap = this.rules.url.exec(src))) {
18953 src = src.substring(cap[0].length);
18954 text = escape(cap[1]);
18956 out += this.renderer.link(href, null, text);
18961 if (cap = this.rules.tag.exec(src)) {
18962 if (!this.inLink && /^<a /i.test(cap[0])) {
18963 this.inLink = true;
18964 } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
18965 this.inLink = false;
18967 src = src.substring(cap[0].length);
18968 out += this.options.sanitize
18969 ? this.options.sanitizer
18970 ? this.options.sanitizer(cap[0])
18977 if (cap = this.rules.link.exec(src)) {
18978 src = src.substring(cap[0].length);
18979 this.inLink = true;
18980 out += this.outputLink(cap, {
18984 this.inLink = false;
18989 if ((cap = this.rules.reflink.exec(src))
18990 || (cap = this.rules.nolink.exec(src))) {
18991 src = src.substring(cap[0].length);
18992 link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
18993 link = this.links[link.toLowerCase()];
18994 if (!link || !link.href) {
18995 out += cap[0].charAt(0);
18996 src = cap[0].substring(1) + src;
18999 this.inLink = true;
19000 out += this.outputLink(cap, link);
19001 this.inLink = false;
19006 if (cap = this.rules.strong.exec(src)) {
19007 src = src.substring(cap[0].length);
19008 out += this.renderer.strong(this.output(cap[2] || cap[1]));
19013 if (cap = this.rules.em.exec(src)) {
19014 src = src.substring(cap[0].length);
19015 out += this.renderer.em(this.output(cap[2] || cap[1]));
19020 if (cap = this.rules.code.exec(src)) {
19021 src = src.substring(cap[0].length);
19022 out += this.renderer.codespan(escape(cap[2], true));
19027 if (cap = this.rules.br.exec(src)) {
19028 src = src.substring(cap[0].length);
19029 out += this.renderer.br();
19034 if (cap = this.rules.del.exec(src)) {
19035 src = src.substring(cap[0].length);
19036 out += this.renderer.del(this.output(cap[1]));
19041 if (cap = this.rules.text.exec(src)) {
19042 src = src.substring(cap[0].length);
19043 out += this.renderer.text(escape(this.smartypants(cap[0])));
19049 Error('Infinite loop on byte: ' + src.charCodeAt(0));
19060 InlineLexer.prototype.outputLink = function(cap, link) {
19061 var href = escape(link.href)
19062 , title = link.title ? escape(link.title) : null;
19064 return cap[0].charAt(0) !== '!'
19065 ? this.renderer.link(href, title, this.output(cap[1]))
19066 : this.renderer.image(href, title, escape(cap[1]));
19070 * Smartypants Transformations
19073 InlineLexer.prototype.smartypants = function(text) {
19074 if (!this.options.smartypants) { return text; }
19077 .replace(/---/g, '\u2014')
19079 .replace(/--/g, '\u2013')
19081 .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
19082 // closing singles & apostrophes
19083 .replace(/'/g, '\u2019')
19085 .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
19087 .replace(/"/g, '\u201d')
19089 .replace(/\.{3}/g, '\u2026');
19096 InlineLexer.prototype.mangle = function(text) {
19097 if (!this.options.mangle) { return text; }
19103 for (; i < l; i++) {
19104 ch = text.charCodeAt(i);
19105 if (Math.random() > 0.5) {
19106 ch = 'x' + ch.toString(16);
19108 out += '&#' + ch + ';';
19119 * eval:var:Renderer
19122 var Renderer = function (options) {
19123 this.options = options || {};
19126 Renderer.prototype.code = function(code, lang, escaped) {
19127 if (this.options.highlight) {
19128 var out = this.options.highlight(code, lang);
19129 if (out != null && out !== code) {
19134 // hack!!! - it's already escapeD?
19139 return '<pre><code>'
19140 + (escaped ? code : escape(code, true))
19141 + '\n</code></pre>';
19144 return '<pre><code class="'
19145 + this.options.langPrefix
19146 + escape(lang, true)
19148 + (escaped ? code : escape(code, true))
19149 + '\n</code></pre>\n';
19152 Renderer.prototype.blockquote = function(quote) {
19153 return '<blockquote>\n' + quote + '</blockquote>\n';
19156 Renderer.prototype.html = function(html) {
19160 Renderer.prototype.heading = function(text, level, raw) {
19164 + this.options.headerPrefix
19165 + raw.toLowerCase().replace(/[^\w]+/g, '-')
19173 Renderer.prototype.hr = function() {
19174 return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
19177 Renderer.prototype.list = function(body, ordered) {
19178 var type = ordered ? 'ol' : 'ul';
19179 return '<' + type + '>\n' + body + '</' + type + '>\n';
19182 Renderer.prototype.listitem = function(text) {
19183 return '<li>' + text + '</li>\n';
19186 Renderer.prototype.paragraph = function(text) {
19187 return '<p>' + text + '</p>\n';
19190 Renderer.prototype.table = function(header, body) {
19191 return '<table class="table table-striped">\n'
19201 Renderer.prototype.tablerow = function(content) {
19202 return '<tr>\n' + content + '</tr>\n';
19205 Renderer.prototype.tablecell = function(content, flags) {
19206 var type = flags.header ? 'th' : 'td';
19207 var tag = flags.align
19208 ? '<' + type + ' style="text-align:' + flags.align + '">'
19209 : '<' + type + '>';
19210 return tag + content + '</' + type + '>\n';
19213 // span level renderer
19214 Renderer.prototype.strong = function(text) {
19215 return '<strong>' + text + '</strong>';
19218 Renderer.prototype.em = function(text) {
19219 return '<em>' + text + '</em>';
19222 Renderer.prototype.codespan = function(text) {
19223 return '<code>' + text + '</code>';
19226 Renderer.prototype.br = function() {
19227 return this.options.xhtml ? '<br/>' : '<br>';
19230 Renderer.prototype.del = function(text) {
19231 return '<del>' + text + '</del>';
19234 Renderer.prototype.link = function(href, title, text) {
19235 if (this.options.sanitize) {
19237 var prot = decodeURIComponent(unescape(href))
19238 .replace(/[^\w:]/g, '')
19243 if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) {
19247 var out = '<a href="' + href + '"';
19249 out += ' title="' + title + '"';
19251 out += '>' + text + '</a>';
19255 Renderer.prototype.image = function(href, title, text) {
19256 var out = '<img src="' + href + '" alt="' + text + '"';
19258 out += ' title="' + title + '"';
19260 out += this.options.xhtml ? '/>' : '>';
19264 Renderer.prototype.text = function(text) {
19269 * Parsing & Compiling
19275 var Parser= function (options) {
19278 this.options = options || marked.defaults;
19279 this.options.renderer = this.options.renderer || new Renderer;
19280 this.renderer = this.options.renderer;
19281 this.renderer.options = this.options;
19285 * Static Parse Method
19288 Parser.parse = function(src, options, renderer) {
19289 var parser = new Parser(options, renderer);
19290 return parser.parse(src);
19297 Parser.prototype.parse = function(src) {
19298 this.inline = new InlineLexer(src.links, this.options, this.renderer);
19299 this.tokens = src.reverse();
19302 while (this.next()) {
19313 Parser.prototype.next = function() {
19314 return this.token = this.tokens.pop();
19318 * Preview Next Token
19321 Parser.prototype.peek = function() {
19322 return this.tokens[this.tokens.length - 1] || 0;
19326 * Parse Text Tokens
19329 Parser.prototype.parseText = function() {
19330 var body = this.token.text;
19332 while (this.peek().type === 'text') {
19333 body += '\n' + this.next().text;
19336 return this.inline.output(body);
19340 * Parse Current Token
19343 Parser.prototype.tok = function() {
19344 switch (this.token.type) {
19349 return this.renderer.hr();
19352 return this.renderer.heading(
19353 this.inline.output(this.token.text),
19358 return this.renderer.code(this.token.text,
19360 this.token.escaped);
19373 for (i = 0; i < this.token.header.length; i++) {
19374 flags = { header: true, align: this.token.align[i] };
19375 cell += this.renderer.tablecell(
19376 this.inline.output(this.token.header[i]),
19377 { header: true, align: this.token.align[i] }
19380 header += this.renderer.tablerow(cell);
19382 for (i = 0; i < this.token.cells.length; i++) {
19383 row = this.token.cells[i];
19386 for (j = 0; j < row.length; j++) {
19387 cell += this.renderer.tablecell(
19388 this.inline.output(row[j]),
19389 { header: false, align: this.token.align[j] }
19393 body += this.renderer.tablerow(cell);
19395 return this.renderer.table(header, body);
19397 case 'blockquote_start': {
19400 while (this.next().type !== 'blockquote_end') {
19401 body += this.tok();
19404 return this.renderer.blockquote(body);
19406 case 'list_start': {
19408 , ordered = this.token.ordered;
19410 while (this.next().type !== 'list_end') {
19411 body += this.tok();
19414 return this.renderer.list(body, ordered);
19416 case 'list_item_start': {
19419 while (this.next().type !== 'list_item_end') {
19420 body += this.token.type === 'text'
19425 return this.renderer.listitem(body);
19427 case 'loose_item_start': {
19430 while (this.next().type !== 'list_item_end') {
19431 body += this.tok();
19434 return this.renderer.listitem(body);
19437 var html = !this.token.pre && !this.options.pedantic
19438 ? this.inline.output(this.token.text)
19440 return this.renderer.html(html);
19442 case 'paragraph': {
19443 return this.renderer.paragraph(this.inline.output(this.token.text));
19446 return this.renderer.paragraph(this.parseText());
19458 var marked = function (src, opt, callback) {
19459 if (callback || typeof opt === 'function') {
19465 opt = merge({}, marked.defaults, opt || {});
19467 var highlight = opt.highlight
19473 tokens = Lexer.lex(src, opt)
19475 return callback(e);
19478 pending = tokens.length;
19482 var done = function(err) {
19484 opt.highlight = highlight;
19485 return callback(err);
19491 out = Parser.parse(tokens, opt);
19496 opt.highlight = highlight;
19500 : callback(null, out);
19503 if (!highlight || highlight.length < 3) {
19507 delete opt.highlight;
19509 if (!pending) { return done(); }
19511 for (; i < tokens.length; i++) {
19513 if (token.type !== 'code') {
19514 return --pending || done();
19516 return highlight(token.text, token.lang, function(err, code) {
19517 if (err) { return done(err); }
19518 if (code == null || code === token.text) {
19519 return --pending || done();
19522 token.escaped = true;
19523 --pending || done();
19531 if (opt) { opt = merge({}, marked.defaults, opt); }
19532 return Parser.parse(Lexer.lex(src, opt), opt);
19534 e.message += '\nPlease report this to https://github.com/chjj/marked.';
19535 if ((opt || marked.defaults).silent) {
19536 return '<p>An error occured:</p><pre>'
19537 + escape(e.message + '', true)
19549 marked.setOptions = function(opt) {
19550 merge(marked.defaults, opt);
19554 marked.defaults = {
19565 langPrefix: 'lang-',
19566 smartypants: false,
19568 renderer: new Renderer,
19576 marked.Parser = Parser;
19577 marked.parser = Parser.parse;
19579 marked.Renderer = Renderer;
19581 marked.Lexer = Lexer;
19582 marked.lexer = Lexer.lex;
19584 marked.InlineLexer = InlineLexer;
19585 marked.inlineLexer = InlineLexer.output;
19587 marked.parse = marked;
19589 Roo.Markdown.marked = marked;
19593 * Ext JS Library 1.1.1
19594 * Copyright(c) 2006-2007, Ext JS, LLC.
19596 * Originally Released Under LGPL - original licence link has changed is not relivant.
19599 * <script type="text/javascript">
19605 * These classes are derivatives of the similarly named classes in the YUI Library.
19606 * The original license:
19607 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
19608 * Code licensed under the BSD License:
19609 * http://developer.yahoo.net/yui/license.txt
19614 var Event=Roo.EventManager;
19615 var Dom=Roo.lib.Dom;
19618 * @class Roo.dd.DragDrop
19619 * @extends Roo.util.Observable
19620 * Defines the interface and base operation of items that that can be
19621 * dragged or can be drop targets. It was designed to be extended, overriding
19622 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
19623 * Up to three html elements can be associated with a DragDrop instance:
19625 * <li>linked element: the element that is passed into the constructor.
19626 * This is the element which defines the boundaries for interaction with
19627 * other DragDrop objects.</li>
19628 * <li>handle element(s): The drag operation only occurs if the element that
19629 * was clicked matches a handle element. By default this is the linked
19630 * element, but there are times that you will want only a portion of the
19631 * linked element to initiate the drag operation, and the setHandleElId()
19632 * method provides a way to define this.</li>
19633 * <li>drag element: this represents the element that would be moved along
19634 * with the cursor during a drag operation. By default, this is the linked
19635 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
19636 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
19639 * This class should not be instantiated until the onload event to ensure that
19640 * the associated elements are available.
19641 * The following would define a DragDrop obj that would interact with any
19642 * other DragDrop obj in the "group1" group:
19644 * dd = new Roo.dd.DragDrop("div1", "group1");
19646 * Since none of the event handlers have been implemented, nothing would
19647 * actually happen if you were to run the code above. Normally you would
19648 * override this class or one of the default implementations, but you can
19649 * also override the methods you want on an instance of the class...
19651 * dd.onDragDrop = function(e, id) {
19652 * alert("dd was dropped on " + id);
19656 * @param {String} id of the element that is linked to this instance
19657 * @param {String} sGroup the group of related DragDrop objects
19658 * @param {object} config an object containing configurable attributes
19659 * Valid properties for DragDrop:
19660 * padding, isTarget, maintainOffset, primaryButtonOnly
19662 Roo.dd.DragDrop = function(id, sGroup, config) {
19664 this.init(id, sGroup, config);
19669 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
19672 * The id of the element associated with this object. This is what we
19673 * refer to as the "linked element" because the size and position of
19674 * this element is used to determine when the drag and drop objects have
19682 * Configuration attributes passed into the constructor
19689 * The id of the element that will be dragged. By default this is same
19690 * as the linked element , but could be changed to another element. Ex:
19692 * @property dragElId
19699 * the id of the element that initiates the drag operation. By default
19700 * this is the linked element, but could be changed to be a child of this
19701 * element. This lets us do things like only starting the drag when the
19702 * header element within the linked html element is clicked.
19703 * @property handleElId
19710 * An associative array of HTML tags that will be ignored if clicked.
19711 * @property invalidHandleTypes
19712 * @type {string: string}
19714 invalidHandleTypes: null,
19717 * An associative array of ids for elements that will be ignored if clicked
19718 * @property invalidHandleIds
19719 * @type {string: string}
19721 invalidHandleIds: null,
19724 * An indexted array of css class names for elements that will be ignored
19726 * @property invalidHandleClasses
19729 invalidHandleClasses: null,
19732 * The linked element's absolute X position at the time the drag was
19734 * @property startPageX
19741 * The linked element's absolute X position at the time the drag was
19743 * @property startPageY
19750 * The group defines a logical collection of DragDrop objects that are
19751 * related. Instances only get events when interacting with other
19752 * DragDrop object in the same group. This lets us define multiple
19753 * groups using a single DragDrop subclass if we want.
19755 * @type {string: string}
19760 * Individual drag/drop instances can be locked. This will prevent
19761 * onmousedown start drag.
19769 * Lock this instance
19772 lock: function() { this.locked = true; },
19775 * Unlock this instace
19778 unlock: function() { this.locked = false; },
19781 * By default, all insances can be a drop target. This can be disabled by
19782 * setting isTarget to false.
19789 * The padding configured for this drag and drop object for calculating
19790 * the drop zone intersection with this object.
19797 * Cached reference to the linked element
19798 * @property _domRef
19804 * Internal typeof flag
19805 * @property __ygDragDrop
19808 __ygDragDrop: true,
19811 * Set to true when horizontal contraints are applied
19812 * @property constrainX
19819 * Set to true when vertical contraints are applied
19820 * @property constrainY
19827 * The left constraint
19835 * The right constraint
19843 * The up constraint
19852 * The down constraint
19860 * Maintain offsets when we resetconstraints. Set to true when you want
19861 * the position of the element relative to its parent to stay the same
19862 * when the page changes
19864 * @property maintainOffset
19867 maintainOffset: false,
19870 * Array of pixel locations the element will snap to if we specified a
19871 * horizontal graduation/interval. This array is generated automatically
19872 * when you define a tick interval.
19879 * Array of pixel locations the element will snap to if we specified a
19880 * vertical graduation/interval. This array is generated automatically
19881 * when you define a tick interval.
19888 * By default the drag and drop instance will only respond to the primary
19889 * button click (left button for a right-handed mouse). Set to true to
19890 * allow drag and drop to start with any mouse click that is propogated
19892 * @property primaryButtonOnly
19895 primaryButtonOnly: true,
19898 * The availabe property is false until the linked dom element is accessible.
19899 * @property available
19905 * By default, drags can only be initiated if the mousedown occurs in the
19906 * region the linked element is. This is done in part to work around a
19907 * bug in some browsers that mis-report the mousedown if the previous
19908 * mouseup happened outside of the window. This property is set to true
19909 * if outer handles are defined.
19911 * @property hasOuterHandles
19915 hasOuterHandles: false,
19918 * Code that executes immediately before the startDrag event
19919 * @method b4StartDrag
19922 b4StartDrag: function(x, y) { },
19925 * Abstract method called after a drag/drop object is clicked
19926 * and the drag or mousedown time thresholds have beeen met.
19927 * @method startDrag
19928 * @param {int} X click location
19929 * @param {int} Y click location
19931 startDrag: function(x, y) { /* override this */ },
19934 * Code that executes immediately before the onDrag event
19938 b4Drag: function(e) { },
19941 * Abstract method called during the onMouseMove event while dragging an
19944 * @param {Event} e the mousemove event
19946 onDrag: function(e) { /* override this */ },
19949 * Abstract method called when this element fist begins hovering over
19950 * another DragDrop obj
19951 * @method onDragEnter
19952 * @param {Event} e the mousemove event
19953 * @param {String|DragDrop[]} id In POINT mode, the element
19954 * id this is hovering over. In INTERSECT mode, an array of one or more
19955 * dragdrop items being hovered over.
19957 onDragEnter: function(e, id) { /* override this */ },
19960 * Code that executes immediately before the onDragOver event
19961 * @method b4DragOver
19964 b4DragOver: function(e) { },
19967 * Abstract method called when this element is hovering over another
19969 * @method onDragOver
19970 * @param {Event} e the mousemove event
19971 * @param {String|DragDrop[]} id In POINT mode, the element
19972 * id this is hovering over. In INTERSECT mode, an array of dd items
19973 * being hovered over.
19975 onDragOver: function(e, id) { /* override this */ },
19978 * Code that executes immediately before the onDragOut event
19979 * @method b4DragOut
19982 b4DragOut: function(e) { },
19985 * Abstract method called when we are no longer hovering over an element
19986 * @method onDragOut
19987 * @param {Event} e the mousemove event
19988 * @param {String|DragDrop[]} id In POINT mode, the element
19989 * id this was hovering over. In INTERSECT mode, an array of dd items
19990 * that the mouse is no longer over.
19992 onDragOut: function(e, id) { /* override this */ },
19995 * Code that executes immediately before the onDragDrop event
19996 * @method b4DragDrop
19999 b4DragDrop: function(e) { },
20002 * Abstract method called when this item is dropped on another DragDrop
20004 * @method onDragDrop
20005 * @param {Event} e the mouseup event
20006 * @param {String|DragDrop[]} id In POINT mode, the element
20007 * id this was dropped on. In INTERSECT mode, an array of dd items this
20010 onDragDrop: function(e, id) { /* override this */ },
20013 * Abstract method called when this item is dropped on an area with no
20015 * @method onInvalidDrop
20016 * @param {Event} e the mouseup event
20018 onInvalidDrop: function(e) { /* override this */ },
20021 * Code that executes immediately before the endDrag event
20022 * @method b4EndDrag
20025 b4EndDrag: function(e) { },
20028 * Fired when we are done dragging the object
20030 * @param {Event} e the mouseup event
20032 endDrag: function(e) { /* override this */ },
20035 * Code executed immediately before the onMouseDown event
20036 * @method b4MouseDown
20037 * @param {Event} e the mousedown event
20040 b4MouseDown: function(e) { },
20043 * Event handler that fires when a drag/drop obj gets a mousedown
20044 * @method onMouseDown
20045 * @param {Event} e the mousedown event
20047 onMouseDown: function(e) { /* override this */ },
20050 * Event handler that fires when a drag/drop obj gets a mouseup
20051 * @method onMouseUp
20052 * @param {Event} e the mouseup event
20054 onMouseUp: function(e) { /* override this */ },
20057 * Override the onAvailable method to do what is needed after the initial
20058 * position was determined.
20059 * @method onAvailable
20061 onAvailable: function () {
20065 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
20068 defaultPadding : {left:0, right:0, top:0, bottom:0},
20071 * Initializes the drag drop object's constraints to restrict movement to a certain element.
20075 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
20076 { dragElId: "existingProxyDiv" });
20077 dd.startDrag = function(){
20078 this.constrainTo("parent-id");
20081 * Or you can initalize it using the {@link Roo.Element} object:
20083 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
20084 startDrag : function(){
20085 this.constrainTo("parent-id");
20089 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
20090 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
20091 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
20092 * an object containing the sides to pad. For example: {right:10, bottom:10}
20093 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
20095 constrainTo : function(constrainTo, pad, inContent){
20096 if(typeof pad == "number"){
20097 pad = {left: pad, right:pad, top:pad, bottom:pad};
20099 pad = pad || this.defaultPadding;
20100 var b = Roo.get(this.getEl()).getBox();
20101 var ce = Roo.get(constrainTo);
20102 var s = ce.getScroll();
20103 var c, cd = ce.dom;
20104 if(cd == document.body){
20105 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
20108 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
20112 var topSpace = b.y - c.y;
20113 var leftSpace = b.x - c.x;
20115 this.resetConstraints();
20116 this.setXConstraint(leftSpace - (pad.left||0), // left
20117 c.width - leftSpace - b.width - (pad.right||0) //right
20119 this.setYConstraint(topSpace - (pad.top||0), //top
20120 c.height - topSpace - b.height - (pad.bottom||0) //bottom
20125 * Returns a reference to the linked element
20127 * @return {HTMLElement} the html element
20129 getEl: function() {
20130 if (!this._domRef) {
20131 this._domRef = Roo.getDom(this.id);
20134 return this._domRef;
20138 * Returns a reference to the actual element to drag. By default this is
20139 * the same as the html element, but it can be assigned to another
20140 * element. An example of this can be found in Roo.dd.DDProxy
20141 * @method getDragEl
20142 * @return {HTMLElement} the html element
20144 getDragEl: function() {
20145 return Roo.getDom(this.dragElId);
20149 * Sets up the DragDrop object. Must be called in the constructor of any
20150 * Roo.dd.DragDrop subclass
20152 * @param id the id of the linked element
20153 * @param {String} sGroup the group of related items
20154 * @param {object} config configuration attributes
20156 init: function(id, sGroup, config) {
20157 this.initTarget(id, sGroup, config);
20158 if (!Roo.isTouch) {
20159 Event.on(this.id, "mousedown", this.handleMouseDown, this);
20161 Event.on(this.id, "touchstart", this.handleMouseDown, this);
20162 // Event.on(this.id, "selectstart", Event.preventDefault);
20166 * Initializes Targeting functionality only... the object does not
20167 * get a mousedown handler.
20168 * @method initTarget
20169 * @param id the id of the linked element
20170 * @param {String} sGroup the group of related items
20171 * @param {object} config configuration attributes
20173 initTarget: function(id, sGroup, config) {
20175 // configuration attributes
20176 this.config = config || {};
20178 // create a local reference to the drag and drop manager
20179 this.DDM = Roo.dd.DDM;
20180 // initialize the groups array
20183 // assume that we have an element reference instead of an id if the
20184 // parameter is not a string
20185 if (typeof id !== "string") {
20192 // add to an interaction group
20193 this.addToGroup((sGroup) ? sGroup : "default");
20195 // We don't want to register this as the handle with the manager
20196 // so we just set the id rather than calling the setter.
20197 this.handleElId = id;
20199 // the linked element is the element that gets dragged by default
20200 this.setDragElId(id);
20202 // by default, clicked anchors will not start drag operations.
20203 this.invalidHandleTypes = { A: "A" };
20204 this.invalidHandleIds = {};
20205 this.invalidHandleClasses = [];
20207 this.applyConfig();
20209 this.handleOnAvailable();
20213 * Applies the configuration parameters that were passed into the constructor.
20214 * This is supposed to happen at each level through the inheritance chain. So
20215 * a DDProxy implentation will execute apply config on DDProxy, DD, and
20216 * DragDrop in order to get all of the parameters that are available in
20218 * @method applyConfig
20220 applyConfig: function() {
20222 // configurable properties:
20223 // padding, isTarget, maintainOffset, primaryButtonOnly
20224 this.padding = this.config.padding || [0, 0, 0, 0];
20225 this.isTarget = (this.config.isTarget !== false);
20226 this.maintainOffset = (this.config.maintainOffset);
20227 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
20232 * Executed when the linked element is available
20233 * @method handleOnAvailable
20236 handleOnAvailable: function() {
20237 this.available = true;
20238 this.resetConstraints();
20239 this.onAvailable();
20243 * Configures the padding for the target zone in px. Effectively expands
20244 * (or reduces) the virtual object size for targeting calculations.
20245 * Supports css-style shorthand; if only one parameter is passed, all sides
20246 * will have that padding, and if only two are passed, the top and bottom
20247 * will have the first param, the left and right the second.
20248 * @method setPadding
20249 * @param {int} iTop Top pad
20250 * @param {int} iRight Right pad
20251 * @param {int} iBot Bot pad
20252 * @param {int} iLeft Left pad
20254 setPadding: function(iTop, iRight, iBot, iLeft) {
20255 // this.padding = [iLeft, iRight, iTop, iBot];
20256 if (!iRight && 0 !== iRight) {
20257 this.padding = [iTop, iTop, iTop, iTop];
20258 } else if (!iBot && 0 !== iBot) {
20259 this.padding = [iTop, iRight, iTop, iRight];
20261 this.padding = [iTop, iRight, iBot, iLeft];
20266 * Stores the initial placement of the linked element.
20267 * @method setInitialPosition
20268 * @param {int} diffX the X offset, default 0
20269 * @param {int} diffY the Y offset, default 0
20271 setInitPosition: function(diffX, diffY) {
20272 var el = this.getEl();
20274 if (!this.DDM.verifyEl(el)) {
20278 var dx = diffX || 0;
20279 var dy = diffY || 0;
20281 var p = Dom.getXY( el );
20283 this.initPageX = p[0] - dx;
20284 this.initPageY = p[1] - dy;
20286 this.lastPageX = p[0];
20287 this.lastPageY = p[1];
20290 this.setStartPosition(p);
20294 * Sets the start position of the element. This is set when the obj
20295 * is initialized, the reset when a drag is started.
20296 * @method setStartPosition
20297 * @param pos current position (from previous lookup)
20300 setStartPosition: function(pos) {
20301 var p = pos || Dom.getXY( this.getEl() );
20302 this.deltaSetXY = null;
20304 this.startPageX = p[0];
20305 this.startPageY = p[1];
20309 * Add this instance to a group of related drag/drop objects. All
20310 * instances belong to at least one group, and can belong to as many
20311 * groups as needed.
20312 * @method addToGroup
20313 * @param sGroup {string} the name of the group
20315 addToGroup: function(sGroup) {
20316 this.groups[sGroup] = true;
20317 this.DDM.regDragDrop(this, sGroup);
20321 * Remove's this instance from the supplied interaction group
20322 * @method removeFromGroup
20323 * @param {string} sGroup The group to drop
20325 removeFromGroup: function(sGroup) {
20326 if (this.groups[sGroup]) {
20327 delete this.groups[sGroup];
20330 this.DDM.removeDDFromGroup(this, sGroup);
20334 * Allows you to specify that an element other than the linked element
20335 * will be moved with the cursor during a drag
20336 * @method setDragElId
20337 * @param id {string} the id of the element that will be used to initiate the drag
20339 setDragElId: function(id) {
20340 this.dragElId = id;
20344 * Allows you to specify a child of the linked element that should be
20345 * used to initiate the drag operation. An example of this would be if
20346 * you have a content div with text and links. Clicking anywhere in the
20347 * content area would normally start the drag operation. Use this method
20348 * to specify that an element inside of the content div is the element
20349 * that starts the drag operation.
20350 * @method setHandleElId
20351 * @param id {string} the id of the element that will be used to
20352 * initiate the drag.
20354 setHandleElId: function(id) {
20355 if (typeof id !== "string") {
20358 this.handleElId = id;
20359 this.DDM.regHandle(this.id, id);
20363 * Allows you to set an element outside of the linked element as a drag
20365 * @method setOuterHandleElId
20366 * @param id the id of the element that will be used to initiate the drag
20368 setOuterHandleElId: function(id) {
20369 if (typeof id !== "string") {
20372 Event.on(id, "mousedown",
20373 this.handleMouseDown, this);
20374 this.setHandleElId(id);
20376 this.hasOuterHandles = true;
20380 * Remove all drag and drop hooks for this element
20383 unreg: function() {
20384 Event.un(this.id, "mousedown",
20385 this.handleMouseDown);
20386 Event.un(this.id, "touchstart",
20387 this.handleMouseDown);
20388 this._domRef = null;
20389 this.DDM._remove(this);
20392 destroy : function(){
20397 * Returns true if this instance is locked, or the drag drop mgr is locked
20398 * (meaning that all drag/drop is disabled on the page.)
20400 * @return {boolean} true if this obj or all drag/drop is locked, else
20403 isLocked: function() {
20404 return (this.DDM.isLocked() || this.locked);
20408 * Fired when this object is clicked
20409 * @method handleMouseDown
20411 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
20414 handleMouseDown: function(e, oDD){
20416 if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
20417 //Roo.log('not touch/ button !=0');
20420 if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
20421 return; // double touch..
20425 if (this.isLocked()) {
20426 //Roo.log('locked');
20430 this.DDM.refreshCache(this.groups);
20431 // Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
20432 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
20433 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
20434 //Roo.log('no outer handes or not over target');
20437 // Roo.log('check validator');
20438 if (this.clickValidator(e)) {
20439 // Roo.log('validate success');
20440 // set the initial element position
20441 this.setStartPosition();
20444 this.b4MouseDown(e);
20445 this.onMouseDown(e);
20447 this.DDM.handleMouseDown(e, this);
20449 this.DDM.stopEvent(e);
20457 clickValidator: function(e) {
20458 var target = e.getTarget();
20459 return ( this.isValidHandleChild(target) &&
20460 (this.id == this.handleElId ||
20461 this.DDM.handleWasClicked(target, this.id)) );
20465 * Allows you to specify a tag name that should not start a drag operation
20466 * when clicked. This is designed to facilitate embedding links within a
20467 * drag handle that do something other than start the drag.
20468 * @method addInvalidHandleType
20469 * @param {string} tagName the type of element to exclude
20471 addInvalidHandleType: function(tagName) {
20472 var type = tagName.toUpperCase();
20473 this.invalidHandleTypes[type] = type;
20477 * Lets you to specify an element id for a child of a drag handle
20478 * that should not initiate a drag
20479 * @method addInvalidHandleId
20480 * @param {string} id the element id of the element you wish to ignore
20482 addInvalidHandleId: function(id) {
20483 if (typeof id !== "string") {
20486 this.invalidHandleIds[id] = id;
20490 * Lets you specify a css class of elements that will not initiate a drag
20491 * @method addInvalidHandleClass
20492 * @param {string} cssClass the class of the elements you wish to ignore
20494 addInvalidHandleClass: function(cssClass) {
20495 this.invalidHandleClasses.push(cssClass);
20499 * Unsets an excluded tag name set by addInvalidHandleType
20500 * @method removeInvalidHandleType
20501 * @param {string} tagName the type of element to unexclude
20503 removeInvalidHandleType: function(tagName) {
20504 var type = tagName.toUpperCase();
20505 // this.invalidHandleTypes[type] = null;
20506 delete this.invalidHandleTypes[type];
20510 * Unsets an invalid handle id
20511 * @method removeInvalidHandleId
20512 * @param {string} id the id of the element to re-enable
20514 removeInvalidHandleId: function(id) {
20515 if (typeof id !== "string") {
20518 delete this.invalidHandleIds[id];
20522 * Unsets an invalid css class
20523 * @method removeInvalidHandleClass
20524 * @param {string} cssClass the class of the element(s) you wish to
20527 removeInvalidHandleClass: function(cssClass) {
20528 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
20529 if (this.invalidHandleClasses[i] == cssClass) {
20530 delete this.invalidHandleClasses[i];
20536 * Checks the tag exclusion list to see if this click should be ignored
20537 * @method isValidHandleChild
20538 * @param {HTMLElement} node the HTMLElement to evaluate
20539 * @return {boolean} true if this is a valid tag type, false if not
20541 isValidHandleChild: function(node) {
20544 // var n = (node.nodeName == "#text") ? node.parentNode : node;
20547 nodeName = node.nodeName.toUpperCase();
20549 nodeName = node.nodeName;
20551 valid = valid && !this.invalidHandleTypes[nodeName];
20552 valid = valid && !this.invalidHandleIds[node.id];
20554 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
20555 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
20564 * Create the array of horizontal tick marks if an interval was specified
20565 * in setXConstraint().
20566 * @method setXTicks
20569 setXTicks: function(iStartX, iTickSize) {
20571 this.xTickSize = iTickSize;
20575 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
20577 this.xTicks[this.xTicks.length] = i;
20582 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
20584 this.xTicks[this.xTicks.length] = i;
20589 this.xTicks.sort(this.DDM.numericSort) ;
20593 * Create the array of vertical tick marks if an interval was specified in
20594 * setYConstraint().
20595 * @method setYTicks
20598 setYTicks: function(iStartY, iTickSize) {
20600 this.yTickSize = iTickSize;
20604 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
20606 this.yTicks[this.yTicks.length] = i;
20611 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
20613 this.yTicks[this.yTicks.length] = i;
20618 this.yTicks.sort(this.DDM.numericSort) ;
20622 * By default, the element can be dragged any place on the screen. Use
20623 * this method to limit the horizontal travel of the element. Pass in
20624 * 0,0 for the parameters if you want to lock the drag to the y axis.
20625 * @method setXConstraint
20626 * @param {int} iLeft the number of pixels the element can move to the left
20627 * @param {int} iRight the number of pixels the element can move to the
20629 * @param {int} iTickSize optional parameter for specifying that the
20631 * should move iTickSize pixels at a time.
20633 setXConstraint: function(iLeft, iRight, iTickSize) {
20634 this.leftConstraint = iLeft;
20635 this.rightConstraint = iRight;
20637 this.minX = this.initPageX - iLeft;
20638 this.maxX = this.initPageX + iRight;
20639 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
20641 this.constrainX = true;
20645 * Clears any constraints applied to this instance. Also clears ticks
20646 * since they can't exist independent of a constraint at this time.
20647 * @method clearConstraints
20649 clearConstraints: function() {
20650 this.constrainX = false;
20651 this.constrainY = false;
20656 * Clears any tick interval defined for this instance
20657 * @method clearTicks
20659 clearTicks: function() {
20660 this.xTicks = null;
20661 this.yTicks = null;
20662 this.xTickSize = 0;
20663 this.yTickSize = 0;
20667 * By default, the element can be dragged any place on the screen. Set
20668 * this to limit the vertical travel of the element. Pass in 0,0 for the
20669 * parameters if you want to lock the drag to the x axis.
20670 * @method setYConstraint
20671 * @param {int} iUp the number of pixels the element can move up
20672 * @param {int} iDown the number of pixels the element can move down
20673 * @param {int} iTickSize optional parameter for specifying that the
20674 * element should move iTickSize pixels at a time.
20676 setYConstraint: function(iUp, iDown, iTickSize) {
20677 this.topConstraint = iUp;
20678 this.bottomConstraint = iDown;
20680 this.minY = this.initPageY - iUp;
20681 this.maxY = this.initPageY + iDown;
20682 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
20684 this.constrainY = true;
20689 * resetConstraints must be called if you manually reposition a dd element.
20690 * @method resetConstraints
20691 * @param {boolean} maintainOffset
20693 resetConstraints: function() {
20696 // Maintain offsets if necessary
20697 if (this.initPageX || this.initPageX === 0) {
20698 // figure out how much this thing has moved
20699 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
20700 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
20702 this.setInitPosition(dx, dy);
20704 // This is the first time we have detected the element's position
20706 this.setInitPosition();
20709 if (this.constrainX) {
20710 this.setXConstraint( this.leftConstraint,
20711 this.rightConstraint,
20715 if (this.constrainY) {
20716 this.setYConstraint( this.topConstraint,
20717 this.bottomConstraint,
20723 * Normally the drag element is moved pixel by pixel, but we can specify
20724 * that it move a number of pixels at a time. This method resolves the
20725 * location when we have it set up like this.
20727 * @param {int} val where we want to place the object
20728 * @param {int[]} tickArray sorted array of valid points
20729 * @return {int} the closest tick
20732 getTick: function(val, tickArray) {
20735 // If tick interval is not defined, it is effectively 1 pixel,
20736 // so we return the value passed to us.
20738 } else if (tickArray[0] >= val) {
20739 // The value is lower than the first tick, so we return the first
20741 return tickArray[0];
20743 for (var i=0, len=tickArray.length; i<len; ++i) {
20745 if (tickArray[next] && tickArray[next] >= val) {
20746 var diff1 = val - tickArray[i];
20747 var diff2 = tickArray[next] - val;
20748 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
20752 // The value is larger than the last tick, so we return the last
20754 return tickArray[tickArray.length - 1];
20761 * @return {string} string representation of the dd obj
20763 toString: function() {
20764 return ("DragDrop " + this.id);
20772 * Ext JS Library 1.1.1
20773 * Copyright(c) 2006-2007, Ext JS, LLC.
20775 * Originally Released Under LGPL - original licence link has changed is not relivant.
20778 * <script type="text/javascript">
20783 * The drag and drop utility provides a framework for building drag and drop
20784 * applications. In addition to enabling drag and drop for specific elements,
20785 * the drag and drop elements are tracked by the manager class, and the
20786 * interactions between the various elements are tracked during the drag and
20787 * the implementing code is notified about these important moments.
20790 // Only load the library once. Rewriting the manager class would orphan
20791 // existing drag and drop instances.
20792 if (!Roo.dd.DragDropMgr) {
20795 * @class Roo.dd.DragDropMgr
20796 * DragDropMgr is a singleton that tracks the element interaction for
20797 * all DragDrop items in the window. Generally, you will not call
20798 * this class directly, but it does have helper methods that could
20799 * be useful in your DragDrop implementations.
20802 Roo.dd.DragDropMgr = function() {
20804 var Event = Roo.EventManager;
20809 * Two dimensional Array of registered DragDrop objects. The first
20810 * dimension is the DragDrop item group, the second the DragDrop
20813 * @type {string: string}
20820 * Array of element ids defined as drag handles. Used to determine
20821 * if the element that generated the mousedown event is actually the
20822 * handle and not the html element itself.
20823 * @property handleIds
20824 * @type {string: string}
20831 * the DragDrop object that is currently being dragged
20832 * @property dragCurrent
20840 * the DragDrop object(s) that are being hovered over
20841 * @property dragOvers
20849 * the X distance between the cursor and the object being dragged
20858 * the Y distance between the cursor and the object being dragged
20867 * Flag to determine if we should prevent the default behavior of the
20868 * events we define. By default this is true, but this can be set to
20869 * false if you need the default behavior (not recommended)
20870 * @property preventDefault
20874 preventDefault: true,
20877 * Flag to determine if we should stop the propagation of the events
20878 * we generate. This is true by default but you may want to set it to
20879 * false if the html element contains other features that require the
20881 * @property stopPropagation
20885 stopPropagation: true,
20888 * Internal flag that is set to true when drag and drop has been
20890 * @property initialized
20897 * All drag and drop can be disabled.
20905 * Called the first time an element is registered.
20911 this.initialized = true;
20915 * In point mode, drag and drop interaction is defined by the
20916 * location of the cursor during the drag/drop
20924 * In intersect mode, drag and drop interactio nis defined by the
20925 * overlap of two or more drag and drop objects.
20926 * @property INTERSECT
20933 * The current drag and drop mode. Default: POINT
20941 * Runs method on all drag and drop objects
20942 * @method _execOnAll
20946 _execOnAll: function(sMethod, args) {
20947 for (var i in this.ids) {
20948 for (var j in this.ids[i]) {
20949 var oDD = this.ids[i][j];
20950 if (! this.isTypeOfDD(oDD)) {
20953 oDD[sMethod].apply(oDD, args);
20959 * Drag and drop initialization. Sets up the global event handlers
20964 _onLoad: function() {
20968 if (!Roo.isTouch) {
20969 Event.on(document, "mouseup", this.handleMouseUp, this, true);
20970 Event.on(document, "mousemove", this.handleMouseMove, this, true);
20972 Event.on(document, "touchend", this.handleMouseUp, this, true);
20973 Event.on(document, "touchmove", this.handleMouseMove, this, true);
20975 Event.on(window, "unload", this._onUnload, this, true);
20976 Event.on(window, "resize", this._onResize, this, true);
20977 // Event.on(window, "mouseout", this._test);
20982 * Reset constraints on all drag and drop objs
20983 * @method _onResize
20987 _onResize: function(e) {
20988 this._execOnAll("resetConstraints", []);
20992 * Lock all drag and drop functionality
20996 lock: function() { this.locked = true; },
20999 * Unlock all drag and drop functionality
21003 unlock: function() { this.locked = false; },
21006 * Is drag and drop locked?
21008 * @return {boolean} True if drag and drop is locked, false otherwise.
21011 isLocked: function() { return this.locked; },
21014 * Location cache that is set for all drag drop objects when a drag is
21015 * initiated, cleared when the drag is finished.
21016 * @property locationCache
21023 * Set useCache to false if you want to force object the lookup of each
21024 * drag and drop linked element constantly during a drag.
21025 * @property useCache
21032 * The number of pixels that the mouse needs to move after the
21033 * mousedown before the drag is initiated. Default=3;
21034 * @property clickPixelThresh
21038 clickPixelThresh: 3,
21041 * The number of milliseconds after the mousedown event to initiate the
21042 * drag if we don't get a mouseup event. Default=1000
21043 * @property clickTimeThresh
21047 clickTimeThresh: 350,
21050 * Flag that indicates that either the drag pixel threshold or the
21051 * mousdown time threshold has been met
21052 * @property dragThreshMet
21057 dragThreshMet: false,
21060 * Timeout used for the click time threshold
21061 * @property clickTimeout
21066 clickTimeout: null,
21069 * The X position of the mousedown event stored for later use when a
21070 * drag threshold is met.
21079 * The Y position of the mousedown event stored for later use when a
21080 * drag threshold is met.
21089 * Each DragDrop instance must be registered with the DragDropMgr.
21090 * This is executed in DragDrop.init()
21091 * @method regDragDrop
21092 * @param {DragDrop} oDD the DragDrop object to register
21093 * @param {String} sGroup the name of the group this element belongs to
21096 regDragDrop: function(oDD, sGroup) {
21097 if (!this.initialized) { this.init(); }
21099 if (!this.ids[sGroup]) {
21100 this.ids[sGroup] = {};
21102 this.ids[sGroup][oDD.id] = oDD;
21106 * Removes the supplied dd instance from the supplied group. Executed
21107 * by DragDrop.removeFromGroup, so don't call this function directly.
21108 * @method removeDDFromGroup
21112 removeDDFromGroup: function(oDD, sGroup) {
21113 if (!this.ids[sGroup]) {
21114 this.ids[sGroup] = {};
21117 var obj = this.ids[sGroup];
21118 if (obj && obj[oDD.id]) {
21119 delete obj[oDD.id];
21124 * Unregisters a drag and drop item. This is executed in
21125 * DragDrop.unreg, use that method instead of calling this directly.
21130 _remove: function(oDD) {
21131 for (var g in oDD.groups) {
21132 if (g && this.ids[g][oDD.id]) {
21133 delete this.ids[g][oDD.id];
21136 delete this.handleIds[oDD.id];
21140 * Each DragDrop handle element must be registered. This is done
21141 * automatically when executing DragDrop.setHandleElId()
21142 * @method regHandle
21143 * @param {String} sDDId the DragDrop id this element is a handle for
21144 * @param {String} sHandleId the id of the element that is the drag
21148 regHandle: function(sDDId, sHandleId) {
21149 if (!this.handleIds[sDDId]) {
21150 this.handleIds[sDDId] = {};
21152 this.handleIds[sDDId][sHandleId] = sHandleId;
21156 * Utility function to determine if a given element has been
21157 * registered as a drag drop item.
21158 * @method isDragDrop
21159 * @param {String} id the element id to check
21160 * @return {boolean} true if this element is a DragDrop item,
21164 isDragDrop: function(id) {
21165 return ( this.getDDById(id) ) ? true : false;
21169 * Returns the drag and drop instances that are in all groups the
21170 * passed in instance belongs to.
21171 * @method getRelated
21172 * @param {DragDrop} p_oDD the obj to get related data for
21173 * @param {boolean} bTargetsOnly if true, only return targetable objs
21174 * @return {DragDrop[]} the related instances
21177 getRelated: function(p_oDD, bTargetsOnly) {
21179 for (var i in p_oDD.groups) {
21180 for (j in this.ids[i]) {
21181 var dd = this.ids[i][j];
21182 if (! this.isTypeOfDD(dd)) {
21185 if (!bTargetsOnly || dd.isTarget) {
21186 oDDs[oDDs.length] = dd;
21195 * Returns true if the specified dd target is a legal target for
21196 * the specifice drag obj
21197 * @method isLegalTarget
21198 * @param {DragDrop} the drag obj
21199 * @param {DragDrop} the target
21200 * @return {boolean} true if the target is a legal target for the
21204 isLegalTarget: function (oDD, oTargetDD) {
21205 var targets = this.getRelated(oDD, true);
21206 for (var i=0, len=targets.length;i<len;++i) {
21207 if (targets[i].id == oTargetDD.id) {
21216 * My goal is to be able to transparently determine if an object is
21217 * typeof DragDrop, and the exact subclass of DragDrop. typeof
21218 * returns "object", oDD.constructor.toString() always returns
21219 * "DragDrop" and not the name of the subclass. So for now it just
21220 * evaluates a well-known variable in DragDrop.
21221 * @method isTypeOfDD
21222 * @param {Object} the object to evaluate
21223 * @return {boolean} true if typeof oDD = DragDrop
21226 isTypeOfDD: function (oDD) {
21227 return (oDD && oDD.__ygDragDrop);
21231 * Utility function to determine if a given element has been
21232 * registered as a drag drop handle for the given Drag Drop object.
21234 * @param {String} id the element id to check
21235 * @return {boolean} true if this element is a DragDrop handle, false
21239 isHandle: function(sDDId, sHandleId) {
21240 return ( this.handleIds[sDDId] &&
21241 this.handleIds[sDDId][sHandleId] );
21245 * Returns the DragDrop instance for a given id
21246 * @method getDDById
21247 * @param {String} id the id of the DragDrop object
21248 * @return {DragDrop} the drag drop object, null if it is not found
21251 getDDById: function(id) {
21252 for (var i in this.ids) {
21253 if (this.ids[i][id]) {
21254 return this.ids[i][id];
21261 * Fired after a registered DragDrop object gets the mousedown event.
21262 * Sets up the events required to track the object being dragged
21263 * @method handleMouseDown
21264 * @param {Event} e the event
21265 * @param oDD the DragDrop object being dragged
21269 handleMouseDown: function(e, oDD) {
21271 Roo.QuickTips.disable();
21273 this.currentTarget = e.getTarget();
21275 this.dragCurrent = oDD;
21277 var el = oDD.getEl();
21279 // track start position
21280 this.startX = e.getPageX();
21281 this.startY = e.getPageY();
21283 this.deltaX = this.startX - el.offsetLeft;
21284 this.deltaY = this.startY - el.offsetTop;
21286 this.dragThreshMet = false;
21288 this.clickTimeout = setTimeout(
21290 var DDM = Roo.dd.DDM;
21291 DDM.startDrag(DDM.startX, DDM.startY);
21293 this.clickTimeThresh );
21297 * Fired when either the drag pixel threshol or the mousedown hold
21298 * time threshold has been met.
21299 * @method startDrag
21300 * @param x {int} the X position of the original mousedown
21301 * @param y {int} the Y position of the original mousedown
21304 startDrag: function(x, y) {
21305 clearTimeout(this.clickTimeout);
21306 if (this.dragCurrent) {
21307 this.dragCurrent.b4StartDrag(x, y);
21308 this.dragCurrent.startDrag(x, y);
21310 this.dragThreshMet = true;
21314 * Internal function to handle the mouseup event. Will be invoked
21315 * from the context of the document.
21316 * @method handleMouseUp
21317 * @param {Event} e the event
21321 handleMouseUp: function(e) {
21324 Roo.QuickTips.enable();
21326 if (! this.dragCurrent) {
21330 clearTimeout(this.clickTimeout);
21332 if (this.dragThreshMet) {
21333 this.fireEvents(e, true);
21343 * Utility to stop event propagation and event default, if these
21344 * features are turned on.
21345 * @method stopEvent
21346 * @param {Event} e the event as returned by this.getEvent()
21349 stopEvent: function(e){
21350 if(this.stopPropagation) {
21351 e.stopPropagation();
21354 if (this.preventDefault) {
21355 e.preventDefault();
21360 * Internal function to clean up event handlers after the drag
21361 * operation is complete
21363 * @param {Event} e the event
21367 stopDrag: function(e) {
21368 // Fire the drag end event for the item that was dragged
21369 if (this.dragCurrent) {
21370 if (this.dragThreshMet) {
21371 this.dragCurrent.b4EndDrag(e);
21372 this.dragCurrent.endDrag(e);
21375 this.dragCurrent.onMouseUp(e);
21378 this.dragCurrent = null;
21379 this.dragOvers = {};
21383 * Internal function to handle the mousemove event. Will be invoked
21384 * from the context of the html element.
21386 * @TODO figure out what we can do about mouse events lost when the
21387 * user drags objects beyond the window boundary. Currently we can
21388 * detect this in internet explorer by verifying that the mouse is
21389 * down during the mousemove event. Firefox doesn't give us the
21390 * button state on the mousemove event.
21391 * @method handleMouseMove
21392 * @param {Event} e the event
21396 handleMouseMove: function(e) {
21397 if (! this.dragCurrent) {
21401 // var button = e.which || e.button;
21403 // check for IE mouseup outside of page boundary
21404 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
21406 return this.handleMouseUp(e);
21409 if (!this.dragThreshMet) {
21410 var diffX = Math.abs(this.startX - e.getPageX());
21411 var diffY = Math.abs(this.startY - e.getPageY());
21412 if (diffX > this.clickPixelThresh ||
21413 diffY > this.clickPixelThresh) {
21414 this.startDrag(this.startX, this.startY);
21418 if (this.dragThreshMet) {
21419 this.dragCurrent.b4Drag(e);
21420 this.dragCurrent.onDrag(e);
21421 if(!this.dragCurrent.moveOnly){
21422 this.fireEvents(e, false);
21432 * Iterates over all of the DragDrop elements to find ones we are
21433 * hovering over or dropping on
21434 * @method fireEvents
21435 * @param {Event} e the event
21436 * @param {boolean} isDrop is this a drop op or a mouseover op?
21440 fireEvents: function(e, isDrop) {
21441 var dc = this.dragCurrent;
21443 // If the user did the mouse up outside of the window, we could
21444 // get here even though we have ended the drag.
21445 if (!dc || dc.isLocked()) {
21449 var pt = e.getPoint();
21451 // cache the previous dragOver array
21457 var enterEvts = [];
21459 // Check to see if the object(s) we were hovering over is no longer
21460 // being hovered over so we can fire the onDragOut event
21461 for (var i in this.dragOvers) {
21463 var ddo = this.dragOvers[i];
21465 if (! this.isTypeOfDD(ddo)) {
21469 if (! this.isOverTarget(pt, ddo, this.mode)) {
21470 outEvts.push( ddo );
21473 oldOvers[i] = true;
21474 delete this.dragOvers[i];
21477 for (var sGroup in dc.groups) {
21479 if ("string" != typeof sGroup) {
21483 for (i in this.ids[sGroup]) {
21484 var oDD = this.ids[sGroup][i];
21485 if (! this.isTypeOfDD(oDD)) {
21489 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
21490 if (this.isOverTarget(pt, oDD, this.mode)) {
21491 // look for drop interactions
21493 dropEvts.push( oDD );
21494 // look for drag enter and drag over interactions
21497 // initial drag over: dragEnter fires
21498 if (!oldOvers[oDD.id]) {
21499 enterEvts.push( oDD );
21500 // subsequent drag overs: dragOver fires
21502 overEvts.push( oDD );
21505 this.dragOvers[oDD.id] = oDD;
21513 if (outEvts.length) {
21514 dc.b4DragOut(e, outEvts);
21515 dc.onDragOut(e, outEvts);
21518 if (enterEvts.length) {
21519 dc.onDragEnter(e, enterEvts);
21522 if (overEvts.length) {
21523 dc.b4DragOver(e, overEvts);
21524 dc.onDragOver(e, overEvts);
21527 if (dropEvts.length) {
21528 dc.b4DragDrop(e, dropEvts);
21529 dc.onDragDrop(e, dropEvts);
21533 // fire dragout events
21535 for (i=0, len=outEvts.length; i<len; ++i) {
21536 dc.b4DragOut(e, outEvts[i].id);
21537 dc.onDragOut(e, outEvts[i].id);
21540 // fire enter events
21541 for (i=0,len=enterEvts.length; i<len; ++i) {
21542 // dc.b4DragEnter(e, oDD.id);
21543 dc.onDragEnter(e, enterEvts[i].id);
21546 // fire over events
21547 for (i=0,len=overEvts.length; i<len; ++i) {
21548 dc.b4DragOver(e, overEvts[i].id);
21549 dc.onDragOver(e, overEvts[i].id);
21552 // fire drop events
21553 for (i=0, len=dropEvts.length; i<len; ++i) {
21554 dc.b4DragDrop(e, dropEvts[i].id);
21555 dc.onDragDrop(e, dropEvts[i].id);
21560 // notify about a drop that did not find a target
21561 if (isDrop && !dropEvts.length) {
21562 dc.onInvalidDrop(e);
21568 * Helper function for getting the best match from the list of drag
21569 * and drop objects returned by the drag and drop events when we are
21570 * in INTERSECT mode. It returns either the first object that the
21571 * cursor is over, or the object that has the greatest overlap with
21572 * the dragged element.
21573 * @method getBestMatch
21574 * @param {DragDrop[]} dds The array of drag and drop objects
21576 * @return {DragDrop} The best single match
21579 getBestMatch: function(dds) {
21581 // Return null if the input is not what we expect
21582 //if (!dds || !dds.length || dds.length == 0) {
21584 // If there is only one item, it wins
21585 //} else if (dds.length == 1) {
21587 var len = dds.length;
21592 // Loop through the targeted items
21593 for (var i=0; i<len; ++i) {
21595 // If the cursor is over the object, it wins. If the
21596 // cursor is over multiple matches, the first one we come
21598 if (dd.cursorIsOver) {
21601 // Otherwise the object with the most overlap wins
21604 winner.overlap.getArea() < dd.overlap.getArea()) {
21615 * Refreshes the cache of the top-left and bottom-right points of the
21616 * drag and drop objects in the specified group(s). This is in the
21617 * format that is stored in the drag and drop instance, so typical
21620 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
21624 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
21626 * @TODO this really should be an indexed array. Alternatively this
21627 * method could accept both.
21628 * @method refreshCache
21629 * @param {Object} groups an associative array of groups to refresh
21632 refreshCache: function(groups) {
21633 for (var sGroup in groups) {
21634 if ("string" != typeof sGroup) {
21637 for (var i in this.ids[sGroup]) {
21638 var oDD = this.ids[sGroup][i];
21640 if (this.isTypeOfDD(oDD)) {
21641 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
21642 var loc = this.getLocation(oDD);
21644 this.locationCache[oDD.id] = loc;
21646 delete this.locationCache[oDD.id];
21647 // this will unregister the drag and drop object if
21648 // the element is not in a usable state
21657 * This checks to make sure an element exists and is in the DOM. The
21658 * main purpose is to handle cases where innerHTML is used to remove
21659 * drag and drop objects from the DOM. IE provides an 'unspecified
21660 * error' when trying to access the offsetParent of such an element
21662 * @param {HTMLElement} el the element to check
21663 * @return {boolean} true if the element looks usable
21666 verifyEl: function(el) {
21671 parent = el.offsetParent;
21674 parent = el.offsetParent;
21685 * Returns a Region object containing the drag and drop element's position
21686 * and size, including the padding configured for it
21687 * @method getLocation
21688 * @param {DragDrop} oDD the drag and drop object to get the
21690 * @return {Roo.lib.Region} a Region object representing the total area
21691 * the element occupies, including any padding
21692 * the instance is configured for.
21695 getLocation: function(oDD) {
21696 if (! this.isTypeOfDD(oDD)) {
21700 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
21703 pos= Roo.lib.Dom.getXY(el);
21711 x2 = x1 + el.offsetWidth;
21713 y2 = y1 + el.offsetHeight;
21715 t = y1 - oDD.padding[0];
21716 r = x2 + oDD.padding[1];
21717 b = y2 + oDD.padding[2];
21718 l = x1 - oDD.padding[3];
21720 return new Roo.lib.Region( t, r, b, l );
21724 * Checks the cursor location to see if it over the target
21725 * @method isOverTarget
21726 * @param {Roo.lib.Point} pt The point to evaluate
21727 * @param {DragDrop} oTarget the DragDrop object we are inspecting
21728 * @return {boolean} true if the mouse is over the target
21732 isOverTarget: function(pt, oTarget, intersect) {
21733 // use cache if available
21734 var loc = this.locationCache[oTarget.id];
21735 if (!loc || !this.useCache) {
21736 loc = this.getLocation(oTarget);
21737 this.locationCache[oTarget.id] = loc;
21745 oTarget.cursorIsOver = loc.contains( pt );
21747 // DragDrop is using this as a sanity check for the initial mousedown
21748 // in this case we are done. In POINT mode, if the drag obj has no
21749 // contraints, we are also done. Otherwise we need to evaluate the
21750 // location of the target as related to the actual location of the
21751 // dragged element.
21752 var dc = this.dragCurrent;
21753 if (!dc || !dc.getTargetCoord ||
21754 (!intersect && !dc.constrainX && !dc.constrainY)) {
21755 return oTarget.cursorIsOver;
21758 oTarget.overlap = null;
21760 // Get the current location of the drag element, this is the
21761 // location of the mouse event less the delta that represents
21762 // where the original mousedown happened on the element. We
21763 // need to consider constraints and ticks as well.
21764 var pos = dc.getTargetCoord(pt.x, pt.y);
21766 var el = dc.getDragEl();
21767 var curRegion = new Roo.lib.Region( pos.y,
21768 pos.x + el.offsetWidth,
21769 pos.y + el.offsetHeight,
21772 var overlap = curRegion.intersect(loc);
21775 oTarget.overlap = overlap;
21776 return (intersect) ? true : oTarget.cursorIsOver;
21783 * unload event handler
21784 * @method _onUnload
21788 _onUnload: function(e, me) {
21789 Roo.dd.DragDropMgr.unregAll();
21793 * Cleans up the drag and drop events and objects.
21798 unregAll: function() {
21800 if (this.dragCurrent) {
21802 this.dragCurrent = null;
21805 this._execOnAll("unreg", []);
21807 for (i in this.elementCache) {
21808 delete this.elementCache[i];
21811 this.elementCache = {};
21816 * A cache of DOM elements
21817 * @property elementCache
21824 * Get the wrapper for the DOM element specified
21825 * @method getElWrapper
21826 * @param {String} id the id of the element to get
21827 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
21829 * @deprecated This wrapper isn't that useful
21832 getElWrapper: function(id) {
21833 var oWrapper = this.elementCache[id];
21834 if (!oWrapper || !oWrapper.el) {
21835 oWrapper = this.elementCache[id] =
21836 new this.ElementWrapper(Roo.getDom(id));
21842 * Returns the actual DOM element
21843 * @method getElement
21844 * @param {String} id the id of the elment to get
21845 * @return {Object} The element
21846 * @deprecated use Roo.getDom instead
21849 getElement: function(id) {
21850 return Roo.getDom(id);
21854 * Returns the style property for the DOM element (i.e.,
21855 * document.getElById(id).style)
21857 * @param {String} id the id of the elment to get
21858 * @return {Object} The style property of the element
21859 * @deprecated use Roo.getDom instead
21862 getCss: function(id) {
21863 var el = Roo.getDom(id);
21864 return (el) ? el.style : null;
21868 * Inner class for cached elements
21869 * @class DragDropMgr.ElementWrapper
21874 ElementWrapper: function(el) {
21879 this.el = el || null;
21884 this.id = this.el && el.id;
21886 * A reference to the style property
21889 this.css = this.el && el.style;
21893 * Returns the X position of an html element
21895 * @param el the element for which to get the position
21896 * @return {int} the X coordinate
21898 * @deprecated use Roo.lib.Dom.getX instead
21901 getPosX: function(el) {
21902 return Roo.lib.Dom.getX(el);
21906 * Returns the Y position of an html element
21908 * @param el the element for which to get the position
21909 * @return {int} the Y coordinate
21910 * @deprecated use Roo.lib.Dom.getY instead
21913 getPosY: function(el) {
21914 return Roo.lib.Dom.getY(el);
21918 * Swap two nodes. In IE, we use the native method, for others we
21919 * emulate the IE behavior
21921 * @param n1 the first node to swap
21922 * @param n2 the other node to swap
21925 swapNode: function(n1, n2) {
21929 var p = n2.parentNode;
21930 var s = n2.nextSibling;
21933 p.insertBefore(n1, n2);
21934 } else if (n2 == n1.nextSibling) {
21935 p.insertBefore(n2, n1);
21937 n1.parentNode.replaceChild(n2, n1);
21938 p.insertBefore(n1, s);
21944 * Returns the current scroll position
21945 * @method getScroll
21949 getScroll: function () {
21950 var t, l, dde=document.documentElement, db=document.body;
21951 if (dde && (dde.scrollTop || dde.scrollLeft)) {
21953 l = dde.scrollLeft;
21960 return { top: t, left: l };
21964 * Returns the specified element style property
21966 * @param {HTMLElement} el the element
21967 * @param {string} styleProp the style property
21968 * @return {string} The value of the style property
21969 * @deprecated use Roo.lib.Dom.getStyle
21972 getStyle: function(el, styleProp) {
21973 return Roo.fly(el).getStyle(styleProp);
21977 * Gets the scrollTop
21978 * @method getScrollTop
21979 * @return {int} the document's scrollTop
21982 getScrollTop: function () { return this.getScroll().top; },
21985 * Gets the scrollLeft
21986 * @method getScrollLeft
21987 * @return {int} the document's scrollTop
21990 getScrollLeft: function () { return this.getScroll().left; },
21993 * Sets the x/y position of an element to the location of the
21996 * @param {HTMLElement} moveEl The element to move
21997 * @param {HTMLElement} targetEl The position reference element
22000 moveToEl: function (moveEl, targetEl) {
22001 var aCoord = Roo.lib.Dom.getXY(targetEl);
22002 Roo.lib.Dom.setXY(moveEl, aCoord);
22006 * Numeric array sort function
22007 * @method numericSort
22010 numericSort: function(a, b) { return (a - b); },
22014 * @property _timeoutCount
22021 * Trying to make the load order less important. Without this we get
22022 * an error if this file is loaded before the Event Utility.
22023 * @method _addListeners
22027 _addListeners: function() {
22028 var DDM = Roo.dd.DDM;
22029 if ( Roo.lib.Event && document ) {
22032 if (DDM._timeoutCount > 2000) {
22034 setTimeout(DDM._addListeners, 10);
22035 if (document && document.body) {
22036 DDM._timeoutCount += 1;
22043 * Recursively searches the immediate parent and all child nodes for
22044 * the handle element in order to determine wheter or not it was
22046 * @method handleWasClicked
22047 * @param node the html element to inspect
22050 handleWasClicked: function(node, id) {
22051 if (this.isHandle(id, node.id)) {
22054 // check to see if this is a text node child of the one we want
22055 var p = node.parentNode;
22058 if (this.isHandle(id, p.id)) {
22073 // shorter alias, save a few bytes
22074 Roo.dd.DDM = Roo.dd.DragDropMgr;
22075 Roo.dd.DDM._addListeners();
22079 * Ext JS Library 1.1.1
22080 * Copyright(c) 2006-2007, Ext JS, LLC.
22082 * Originally Released Under LGPL - original licence link has changed is not relivant.
22085 * <script type="text/javascript">
22090 * A DragDrop implementation where the linked element follows the
22091 * mouse cursor during a drag.
22092 * @extends Roo.dd.DragDrop
22094 * @param {String} id the id of the linked element
22095 * @param {String} sGroup the group of related DragDrop items
22096 * @param {object} config an object containing configurable attributes
22097 * Valid properties for DD:
22100 Roo.dd.DD = function(id, sGroup, config) {
22102 this.init(id, sGroup, config);
22106 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
22109 * When set to true, the utility automatically tries to scroll the browser
22110 * window wehn a drag and drop element is dragged near the viewport boundary.
22111 * Defaults to true.
22118 * Sets the pointer offset to the distance between the linked element's top
22119 * left corner and the location the element was clicked
22120 * @method autoOffset
22121 * @param {int} iPageX the X coordinate of the click
22122 * @param {int} iPageY the Y coordinate of the click
22124 autoOffset: function(iPageX, iPageY) {
22125 var x = iPageX - this.startPageX;
22126 var y = iPageY - this.startPageY;
22127 this.setDelta(x, y);
22131 * Sets the pointer offset. You can call this directly to force the
22132 * offset to be in a particular location (e.g., pass in 0,0 to set it
22133 * to the center of the object)
22135 * @param {int} iDeltaX the distance from the left
22136 * @param {int} iDeltaY the distance from the top
22138 setDelta: function(iDeltaX, iDeltaY) {
22139 this.deltaX = iDeltaX;
22140 this.deltaY = iDeltaY;
22144 * Sets the drag element to the location of the mousedown or click event,
22145 * maintaining the cursor location relative to the location on the element
22146 * that was clicked. Override this if you want to place the element in a
22147 * location other than where the cursor is.
22148 * @method setDragElPos
22149 * @param {int} iPageX the X coordinate of the mousedown or drag event
22150 * @param {int} iPageY the Y coordinate of the mousedown or drag event
22152 setDragElPos: function(iPageX, iPageY) {
22153 // the first time we do this, we are going to check to make sure
22154 // the element has css positioning
22156 var el = this.getDragEl();
22157 this.alignElWithMouse(el, iPageX, iPageY);
22161 * Sets the element to the location of the mousedown or click event,
22162 * maintaining the cursor location relative to the location on the element
22163 * that was clicked. Override this if you want to place the element in a
22164 * location other than where the cursor is.
22165 * @method alignElWithMouse
22166 * @param {HTMLElement} el the element to move
22167 * @param {int} iPageX the X coordinate of the mousedown or drag event
22168 * @param {int} iPageY the Y coordinate of the mousedown or drag event
22170 alignElWithMouse: function(el, iPageX, iPageY) {
22171 var oCoord = this.getTargetCoord(iPageX, iPageY);
22172 var fly = el.dom ? el : Roo.fly(el);
22173 if (!this.deltaSetXY) {
22174 var aCoord = [oCoord.x, oCoord.y];
22176 var newLeft = fly.getLeft(true);
22177 var newTop = fly.getTop(true);
22178 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
22180 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
22183 this.cachePosition(oCoord.x, oCoord.y);
22184 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
22189 * Saves the most recent position so that we can reset the constraints and
22190 * tick marks on-demand. We need to know this so that we can calculate the
22191 * number of pixels the element is offset from its original position.
22192 * @method cachePosition
22193 * @param iPageX the current x position (optional, this just makes it so we
22194 * don't have to look it up again)
22195 * @param iPageY the current y position (optional, this just makes it so we
22196 * don't have to look it up again)
22198 cachePosition: function(iPageX, iPageY) {
22200 this.lastPageX = iPageX;
22201 this.lastPageY = iPageY;
22203 var aCoord = Roo.lib.Dom.getXY(this.getEl());
22204 this.lastPageX = aCoord[0];
22205 this.lastPageY = aCoord[1];
22210 * Auto-scroll the window if the dragged object has been moved beyond the
22211 * visible window boundary.
22212 * @method autoScroll
22213 * @param {int} x the drag element's x position
22214 * @param {int} y the drag element's y position
22215 * @param {int} h the height of the drag element
22216 * @param {int} w the width of the drag element
22219 autoScroll: function(x, y, h, w) {
22222 // The client height
22223 var clientH = Roo.lib.Dom.getViewWidth();
22225 // The client width
22226 var clientW = Roo.lib.Dom.getViewHeight();
22228 // The amt scrolled down
22229 var st = this.DDM.getScrollTop();
22231 // The amt scrolled right
22232 var sl = this.DDM.getScrollLeft();
22234 // Location of the bottom of the element
22237 // Location of the right of the element
22240 // The distance from the cursor to the bottom of the visible area,
22241 // adjusted so that we don't scroll if the cursor is beyond the
22242 // element drag constraints
22243 var toBot = (clientH + st - y - this.deltaY);
22245 // The distance from the cursor to the right of the visible area
22246 var toRight = (clientW + sl - x - this.deltaX);
22249 // How close to the edge the cursor must be before we scroll
22250 // var thresh = (document.all) ? 100 : 40;
22253 // How many pixels to scroll per autoscroll op. This helps to reduce
22254 // clunky scrolling. IE is more sensitive about this ... it needs this
22255 // value to be higher.
22256 var scrAmt = (document.all) ? 80 : 30;
22258 // Scroll down if we are near the bottom of the visible page and the
22259 // obj extends below the crease
22260 if ( bot > clientH && toBot < thresh ) {
22261 window.scrollTo(sl, st + scrAmt);
22264 // Scroll up if the window is scrolled down and the top of the object
22265 // goes above the top border
22266 if ( y < st && st > 0 && y - st < thresh ) {
22267 window.scrollTo(sl, st - scrAmt);
22270 // Scroll right if the obj is beyond the right border and the cursor is
22271 // near the border.
22272 if ( right > clientW && toRight < thresh ) {
22273 window.scrollTo(sl + scrAmt, st);
22276 // Scroll left if the window has been scrolled to the right and the obj
22277 // extends past the left border
22278 if ( x < sl && sl > 0 && x - sl < thresh ) {
22279 window.scrollTo(sl - scrAmt, st);
22285 * Finds the location the element should be placed if we want to move
22286 * it to where the mouse location less the click offset would place us.
22287 * @method getTargetCoord
22288 * @param {int} iPageX the X coordinate of the click
22289 * @param {int} iPageY the Y coordinate of the click
22290 * @return an object that contains the coordinates (Object.x and Object.y)
22293 getTargetCoord: function(iPageX, iPageY) {
22296 var x = iPageX - this.deltaX;
22297 var y = iPageY - this.deltaY;
22299 if (this.constrainX) {
22300 if (x < this.minX) { x = this.minX; }
22301 if (x > this.maxX) { x = this.maxX; }
22304 if (this.constrainY) {
22305 if (y < this.minY) { y = this.minY; }
22306 if (y > this.maxY) { y = this.maxY; }
22309 x = this.getTick(x, this.xTicks);
22310 y = this.getTick(y, this.yTicks);
22317 * Sets up config options specific to this class. Overrides
22318 * Roo.dd.DragDrop, but all versions of this method through the
22319 * inheritance chain are called
22321 applyConfig: function() {
22322 Roo.dd.DD.superclass.applyConfig.call(this);
22323 this.scroll = (this.config.scroll !== false);
22327 * Event that fires prior to the onMouseDown event. Overrides
22330 b4MouseDown: function(e) {
22331 // this.resetConstraints();
22332 this.autoOffset(e.getPageX(),
22337 * Event that fires prior to the onDrag event. Overrides
22340 b4Drag: function(e) {
22341 this.setDragElPos(e.getPageX(),
22345 toString: function() {
22346 return ("DD " + this.id);
22349 //////////////////////////////////////////////////////////////////////////
22350 // Debugging ygDragDrop events that can be overridden
22351 //////////////////////////////////////////////////////////////////////////
22353 startDrag: function(x, y) {
22356 onDrag: function(e) {
22359 onDragEnter: function(e, id) {
22362 onDragOver: function(e, id) {
22365 onDragOut: function(e, id) {
22368 onDragDrop: function(e, id) {
22371 endDrag: function(e) {
22378 * Ext JS Library 1.1.1
22379 * Copyright(c) 2006-2007, Ext JS, LLC.
22381 * Originally Released Under LGPL - original licence link has changed is not relivant.
22384 * <script type="text/javascript">
22388 * @class Roo.dd.DDProxy
22389 * A DragDrop implementation that inserts an empty, bordered div into
22390 * the document that follows the cursor during drag operations. At the time of
22391 * the click, the frame div is resized to the dimensions of the linked html
22392 * element, and moved to the exact location of the linked element.
22394 * References to the "frame" element refer to the single proxy element that
22395 * was created to be dragged in place of all DDProxy elements on the
22398 * @extends Roo.dd.DD
22400 * @param {String} id the id of the linked html element
22401 * @param {String} sGroup the group of related DragDrop objects
22402 * @param {object} config an object containing configurable attributes
22403 * Valid properties for DDProxy in addition to those in DragDrop:
22404 * resizeFrame, centerFrame, dragElId
22406 Roo.dd.DDProxy = function(id, sGroup, config) {
22408 this.init(id, sGroup, config);
22414 * The default drag frame div id
22415 * @property Roo.dd.DDProxy.dragElId
22419 Roo.dd.DDProxy.dragElId = "ygddfdiv";
22421 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
22424 * By default we resize the drag frame to be the same size as the element
22425 * we want to drag (this is to get the frame effect). We can turn it off
22426 * if we want a different behavior.
22427 * @property resizeFrame
22433 * By default the frame is positioned exactly where the drag element is, so
22434 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
22435 * you do not have constraints on the obj is to have the drag frame centered
22436 * around the cursor. Set centerFrame to true for this effect.
22437 * @property centerFrame
22440 centerFrame: false,
22443 * Creates the proxy element if it does not yet exist
22444 * @method createFrame
22446 createFrame: function() {
22448 var body = document.body;
22450 if (!body || !body.firstChild) {
22451 setTimeout( function() { self.createFrame(); }, 50 );
22455 var div = this.getDragEl();
22458 div = document.createElement("div");
22459 div.id = this.dragElId;
22462 s.position = "absolute";
22463 s.visibility = "hidden";
22465 s.border = "2px solid #aaa";
22468 // appendChild can blow up IE if invoked prior to the window load event
22469 // while rendering a table. It is possible there are other scenarios
22470 // that would cause this to happen as well.
22471 body.insertBefore(div, body.firstChild);
22476 * Initialization for the drag frame element. Must be called in the
22477 * constructor of all subclasses
22478 * @method initFrame
22480 initFrame: function() {
22481 this.createFrame();
22484 applyConfig: function() {
22485 Roo.dd.DDProxy.superclass.applyConfig.call(this);
22487 this.resizeFrame = (this.config.resizeFrame !== false);
22488 this.centerFrame = (this.config.centerFrame);
22489 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
22493 * Resizes the drag frame to the dimensions of the clicked object, positions
22494 * it over the object, and finally displays it
22495 * @method showFrame
22496 * @param {int} iPageX X click position
22497 * @param {int} iPageY Y click position
22500 showFrame: function(iPageX, iPageY) {
22501 var el = this.getEl();
22502 var dragEl = this.getDragEl();
22503 var s = dragEl.style;
22505 this._resizeProxy();
22507 if (this.centerFrame) {
22508 this.setDelta( Math.round(parseInt(s.width, 10)/2),
22509 Math.round(parseInt(s.height, 10)/2) );
22512 this.setDragElPos(iPageX, iPageY);
22514 Roo.fly(dragEl).show();
22518 * The proxy is automatically resized to the dimensions of the linked
22519 * element when a drag is initiated, unless resizeFrame is set to false
22520 * @method _resizeProxy
22523 _resizeProxy: function() {
22524 if (this.resizeFrame) {
22525 var el = this.getEl();
22526 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
22530 // overrides Roo.dd.DragDrop
22531 b4MouseDown: function(e) {
22532 var x = e.getPageX();
22533 var y = e.getPageY();
22534 this.autoOffset(x, y);
22535 this.setDragElPos(x, y);
22538 // overrides Roo.dd.DragDrop
22539 b4StartDrag: function(x, y) {
22540 // show the drag frame
22541 this.showFrame(x, y);
22544 // overrides Roo.dd.DragDrop
22545 b4EndDrag: function(e) {
22546 Roo.fly(this.getDragEl()).hide();
22549 // overrides Roo.dd.DragDrop
22550 // By default we try to move the element to the last location of the frame.
22551 // This is so that the default behavior mirrors that of Roo.dd.DD.
22552 endDrag: function(e) {
22554 var lel = this.getEl();
22555 var del = this.getDragEl();
22557 // Show the drag frame briefly so we can get its position
22558 del.style.visibility = "";
22561 // Hide the linked element before the move to get around a Safari
22563 lel.style.visibility = "hidden";
22564 Roo.dd.DDM.moveToEl(lel, del);
22565 del.style.visibility = "hidden";
22566 lel.style.visibility = "";
22571 beforeMove : function(){
22575 afterDrag : function(){
22579 toString: function() {
22580 return ("DDProxy " + this.id);
22586 * Ext JS Library 1.1.1
22587 * Copyright(c) 2006-2007, Ext JS, LLC.
22589 * Originally Released Under LGPL - original licence link has changed is not relivant.
22592 * <script type="text/javascript">
22596 * @class Roo.dd.DDTarget
22597 * A DragDrop implementation that does not move, but can be a drop
22598 * target. You would get the same result by simply omitting implementation
22599 * for the event callbacks, but this way we reduce the processing cost of the
22600 * event listener and the callbacks.
22601 * @extends Roo.dd.DragDrop
22603 * @param {String} id the id of the element that is a drop target
22604 * @param {String} sGroup the group of related DragDrop objects
22605 * @param {object} config an object containing configurable attributes
22606 * Valid properties for DDTarget in addition to those in
22610 Roo.dd.DDTarget = function(id, sGroup, config) {
22612 this.initTarget(id, sGroup, config);
22614 if (config && (config.listeners || config.events)) {
22615 Roo.dd.DragDrop.superclass.constructor.call(this, {
22616 listeners : config.listeners || {},
22617 events : config.events || {}
22622 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
22623 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
22624 toString: function() {
22625 return ("DDTarget " + this.id);
22630 * Ext JS Library 1.1.1
22631 * Copyright(c) 2006-2007, Ext JS, LLC.
22633 * Originally Released Under LGPL - original licence link has changed is not relivant.
22636 * <script type="text/javascript">
22641 * @class Roo.dd.ScrollManager
22642 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
22643 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
22646 Roo.dd.ScrollManager = function(){
22647 var ddm = Roo.dd.DragDropMgr;
22654 var onStop = function(e){
22659 var triggerRefresh = function(){
22660 if(ddm.dragCurrent){
22661 ddm.refreshCache(ddm.dragCurrent.groups);
22665 var doScroll = function(){
22666 if(ddm.dragCurrent){
22667 var dds = Roo.dd.ScrollManager;
22669 if(proc.el.scroll(proc.dir, dds.increment)){
22673 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
22678 var clearProc = function(){
22680 clearInterval(proc.id);
22687 var startProc = function(el, dir){
22688 Roo.log('scroll startproc');
22692 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
22695 var onFire = function(e, isDrop){
22697 if(isDrop || !ddm.dragCurrent){ return; }
22698 var dds = Roo.dd.ScrollManager;
22699 if(!dragEl || dragEl != ddm.dragCurrent){
22700 dragEl = ddm.dragCurrent;
22701 // refresh regions on drag start
22702 dds.refreshCache();
22705 var xy = Roo.lib.Event.getXY(e);
22706 var pt = new Roo.lib.Point(xy[0], xy[1]);
22707 for(var id in els){
22708 var el = els[id], r = el._region;
22709 if(r && r.contains(pt) && el.isScrollable()){
22710 if(r.bottom - pt.y <= dds.thresh){
22712 startProc(el, "down");
22715 }else if(r.right - pt.x <= dds.thresh){
22717 startProc(el, "left");
22720 }else if(pt.y - r.top <= dds.thresh){
22722 startProc(el, "up");
22725 }else if(pt.x - r.left <= dds.thresh){
22727 startProc(el, "right");
22736 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
22737 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
22741 * Registers new overflow element(s) to auto scroll
22742 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
22744 register : function(el){
22745 if(el instanceof Array){
22746 for(var i = 0, len = el.length; i < len; i++) {
22747 this.register(el[i]);
22753 Roo.dd.ScrollManager.els = els;
22757 * Unregisters overflow element(s) so they are no longer scrolled
22758 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
22760 unregister : function(el){
22761 if(el instanceof Array){
22762 for(var i = 0, len = el.length; i < len; i++) {
22763 this.unregister(el[i]);
22772 * The number of pixels from the edge of a container the pointer needs to be to
22773 * trigger scrolling (defaults to 25)
22779 * The number of pixels to scroll in each scroll increment (defaults to 50)
22785 * The frequency of scrolls in milliseconds (defaults to 500)
22791 * True to animate the scroll (defaults to true)
22797 * The animation duration in seconds -
22798 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
22804 * Manually trigger a cache refresh.
22806 refreshCache : function(){
22807 for(var id in els){
22808 if(typeof els[id] == 'object'){ // for people extending the object prototype
22809 els[id]._region = els[id].getRegion();
22816 * Ext JS Library 1.1.1
22817 * Copyright(c) 2006-2007, Ext JS, LLC.
22819 * Originally Released Under LGPL - original licence link has changed is not relivant.
22822 * <script type="text/javascript">
22827 * @class Roo.dd.Registry
22828 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
22829 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
22832 Roo.dd.Registry = function(){
22835 var autoIdSeed = 0;
22837 var getId = function(el, autogen){
22838 if(typeof el == "string"){
22842 if(!id && autogen !== false){
22843 id = "roodd-" + (++autoIdSeed);
22851 * Register a drag drop element
22852 * @param {String|HTMLElement} element The id or DOM node to register
22853 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
22854 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
22855 * knows how to interpret, plus there are some specific properties known to the Registry that should be
22856 * populated in the data object (if applicable):
22858 Value Description<br />
22859 --------- ------------------------------------------<br />
22860 handles Array of DOM nodes that trigger dragging<br />
22861 for the element being registered<br />
22862 isHandle True if the element passed in triggers<br />
22863 dragging itself, else false
22866 register : function(el, data){
22868 if(typeof el == "string"){
22869 el = document.getElementById(el);
22872 elements[getId(el)] = data;
22873 if(data.isHandle !== false){
22874 handles[data.ddel.id] = data;
22877 var hs = data.handles;
22878 for(var i = 0, len = hs.length; i < len; i++){
22879 handles[getId(hs[i])] = data;
22885 * Unregister a drag drop element
22886 * @param {String|HTMLElement} element The id or DOM node to unregister
22888 unregister : function(el){
22889 var id = getId(el, false);
22890 var data = elements[id];
22892 delete elements[id];
22894 var hs = data.handles;
22895 for(var i = 0, len = hs.length; i < len; i++){
22896 delete handles[getId(hs[i], false)];
22903 * Returns the handle registered for a DOM Node by id
22904 * @param {String|HTMLElement} id The DOM node or id to look up
22905 * @return {Object} handle The custom handle data
22907 getHandle : function(id){
22908 if(typeof id != "string"){ // must be element?
22911 return handles[id];
22915 * Returns the handle that is registered for the DOM node that is the target of the event
22916 * @param {Event} e The event
22917 * @return {Object} handle The custom handle data
22919 getHandleFromEvent : function(e){
22920 var t = Roo.lib.Event.getTarget(e);
22921 return t ? handles[t.id] : null;
22925 * Returns a custom data object that is registered for a DOM node by id
22926 * @param {String|HTMLElement} id The DOM node or id to look up
22927 * @return {Object} data The custom data
22929 getTarget : function(id){
22930 if(typeof id != "string"){ // must be element?
22933 return elements[id];
22937 * Returns a custom data object that is registered for the DOM node that is the target of the event
22938 * @param {Event} e The event
22939 * @return {Object} data The custom data
22941 getTargetFromEvent : function(e){
22942 var t = Roo.lib.Event.getTarget(e);
22943 return t ? elements[t.id] || handles[t.id] : null;
22948 * Ext JS Library 1.1.1
22949 * Copyright(c) 2006-2007, Ext JS, LLC.
22951 * Originally Released Under LGPL - original licence link has changed is not relivant.
22954 * <script type="text/javascript">
22959 * @class Roo.dd.StatusProxy
22960 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
22961 * default drag proxy used by all Roo.dd components.
22963 * @param {Object} config
22965 Roo.dd.StatusProxy = function(config){
22966 Roo.apply(this, config);
22967 this.id = this.id || Roo.id();
22968 this.el = new Roo.Layer({
22970 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
22971 {tag: "div", cls: "x-dd-drop-icon"},
22972 {tag: "div", cls: "x-dd-drag-ghost"}
22975 shadow: !config || config.shadow !== false
22977 this.ghost = Roo.get(this.el.dom.childNodes[1]);
22978 this.dropStatus = this.dropNotAllowed;
22981 Roo.dd.StatusProxy.prototype = {
22983 * @cfg {String} dropAllowed
22984 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
22986 dropAllowed : "x-dd-drop-ok",
22988 * @cfg {String} dropNotAllowed
22989 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
22991 dropNotAllowed : "x-dd-drop-nodrop",
22994 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
22995 * over the current target element.
22996 * @param {String} cssClass The css class for the new drop status indicator image
22998 setStatus : function(cssClass){
22999 cssClass = cssClass || this.dropNotAllowed;
23000 if(this.dropStatus != cssClass){
23001 this.el.replaceClass(this.dropStatus, cssClass);
23002 this.dropStatus = cssClass;
23007 * Resets the status indicator to the default dropNotAllowed value
23008 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
23010 reset : function(clearGhost){
23011 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
23012 this.dropStatus = this.dropNotAllowed;
23014 this.ghost.update("");
23019 * Updates the contents of the ghost element
23020 * @param {String} html The html that will replace the current innerHTML of the ghost element
23022 update : function(html){
23023 if(typeof html == "string"){
23024 this.ghost.update(html);
23026 this.ghost.update("");
23027 html.style.margin = "0";
23028 this.ghost.dom.appendChild(html);
23030 // ensure float = none set?? cant remember why though.
23031 var el = this.ghost.dom.firstChild;
23033 Roo.fly(el).setStyle('float', 'none');
23038 * Returns the underlying proxy {@link Roo.Layer}
23039 * @return {Roo.Layer} el
23041 getEl : function(){
23046 * Returns the ghost element
23047 * @return {Roo.Element} el
23049 getGhost : function(){
23055 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
23057 hide : function(clear){
23065 * Stops the repair animation if it's currently running
23068 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
23074 * Displays this proxy
23081 * Force the Layer to sync its shadow and shim positions to the element
23088 * Causes the proxy to return to its position of origin via an animation. Should be called after an
23089 * invalid drop operation by the item being dragged.
23090 * @param {Array} xy The XY position of the element ([x, y])
23091 * @param {Function} callback The function to call after the repair is complete
23092 * @param {Object} scope The scope in which to execute the callback
23094 repair : function(xy, callback, scope){
23095 this.callback = callback;
23096 this.scope = scope;
23097 if(xy && this.animRepair !== false){
23098 this.el.addClass("x-dd-drag-repair");
23099 this.el.hideUnders(true);
23100 this.anim = this.el.shift({
23101 duration: this.repairDuration || .5,
23105 callback: this.afterRepair,
23109 this.afterRepair();
23114 afterRepair : function(){
23116 if(typeof this.callback == "function"){
23117 this.callback.call(this.scope || this);
23119 this.callback = null;
23124 * Ext JS Library 1.1.1
23125 * Copyright(c) 2006-2007, Ext JS, LLC.
23127 * Originally Released Under LGPL - original licence link has changed is not relivant.
23130 * <script type="text/javascript">
23134 * @class Roo.dd.DragSource
23135 * @extends Roo.dd.DDProxy
23136 * A simple class that provides the basic implementation needed to make any element draggable.
23138 * @param {String/HTMLElement/Element} el The container element
23139 * @param {Object} config
23141 Roo.dd.DragSource = function(el, config){
23142 this.el = Roo.get(el);
23143 this.dragData = {};
23145 Roo.apply(this, config);
23148 this.proxy = new Roo.dd.StatusProxy();
23151 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
23152 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
23154 this.dragging = false;
23157 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
23159 * @cfg {String} dropAllowed
23160 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
23162 dropAllowed : "x-dd-drop-ok",
23164 * @cfg {String} dropNotAllowed
23165 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
23167 dropNotAllowed : "x-dd-drop-nodrop",
23170 * Returns the data object associated with this drag source
23171 * @return {Object} data An object containing arbitrary data
23173 getDragData : function(e){
23174 return this.dragData;
23178 onDragEnter : function(e, id){
23179 var target = Roo.dd.DragDropMgr.getDDById(id);
23180 this.cachedTarget = target;
23181 if(this.beforeDragEnter(target, e, id) !== false){
23182 if(target.isNotifyTarget){
23183 var status = target.notifyEnter(this, e, this.dragData);
23184 this.proxy.setStatus(status);
23186 this.proxy.setStatus(this.dropAllowed);
23189 if(this.afterDragEnter){
23191 * An empty function by default, but provided so that you can perform a custom action
23192 * when the dragged item enters the drop target by providing an implementation.
23193 * @param {Roo.dd.DragDrop} target The drop target
23194 * @param {Event} e The event object
23195 * @param {String} id The id of the dragged element
23196 * @method afterDragEnter
23198 this.afterDragEnter(target, e, id);
23204 * An empty function by default, but provided so that you can perform a custom action
23205 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
23206 * @param {Roo.dd.DragDrop} target The drop target
23207 * @param {Event} e The event object
23208 * @param {String} id The id of the dragged element
23209 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23211 beforeDragEnter : function(target, e, id){
23216 alignElWithMouse: function() {
23217 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
23222 onDragOver : function(e, id){
23223 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
23224 if(this.beforeDragOver(target, e, id) !== false){
23225 if(target.isNotifyTarget){
23226 var status = target.notifyOver(this, e, this.dragData);
23227 this.proxy.setStatus(status);
23230 if(this.afterDragOver){
23232 * An empty function by default, but provided so that you can perform a custom action
23233 * while the dragged item is over the drop target by providing an implementation.
23234 * @param {Roo.dd.DragDrop} target The drop target
23235 * @param {Event} e The event object
23236 * @param {String} id The id of the dragged element
23237 * @method afterDragOver
23239 this.afterDragOver(target, e, id);
23245 * An empty function by default, but provided so that you can perform a custom action
23246 * while the dragged item is over the drop target and optionally cancel the onDragOver.
23247 * @param {Roo.dd.DragDrop} target The drop target
23248 * @param {Event} e The event object
23249 * @param {String} id The id of the dragged element
23250 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23252 beforeDragOver : function(target, e, id){
23257 onDragOut : function(e, id){
23258 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
23259 if(this.beforeDragOut(target, e, id) !== false){
23260 if(target.isNotifyTarget){
23261 target.notifyOut(this, e, this.dragData);
23263 this.proxy.reset();
23264 if(this.afterDragOut){
23266 * An empty function by default, but provided so that you can perform a custom action
23267 * after the dragged item is dragged out of the target without dropping.
23268 * @param {Roo.dd.DragDrop} target The drop target
23269 * @param {Event} e The event object
23270 * @param {String} id The id of the dragged element
23271 * @method afterDragOut
23273 this.afterDragOut(target, e, id);
23276 this.cachedTarget = null;
23280 * An empty function by default, but provided so that you can perform a custom action before the dragged
23281 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
23282 * @param {Roo.dd.DragDrop} target The drop target
23283 * @param {Event} e The event object
23284 * @param {String} id The id of the dragged element
23285 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23287 beforeDragOut : function(target, e, id){
23292 onDragDrop : function(e, id){
23293 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
23294 if(this.beforeDragDrop(target, e, id) !== false){
23295 if(target.isNotifyTarget){
23296 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
23297 this.onValidDrop(target, e, id);
23299 this.onInvalidDrop(target, e, id);
23302 this.onValidDrop(target, e, id);
23305 if(this.afterDragDrop){
23307 * An empty function by default, but provided so that you can perform a custom action
23308 * after a valid drag drop has occurred by providing an implementation.
23309 * @param {Roo.dd.DragDrop} target The drop target
23310 * @param {Event} e The event object
23311 * @param {String} id The id of the dropped element
23312 * @method afterDragDrop
23314 this.afterDragDrop(target, e, id);
23317 delete this.cachedTarget;
23321 * An empty function by default, but provided so that you can perform a custom action before the dragged
23322 * item is dropped onto the target and optionally cancel the onDragDrop.
23323 * @param {Roo.dd.DragDrop} target The drop target
23324 * @param {Event} e The event object
23325 * @param {String} id The id of the dragged element
23326 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
23328 beforeDragDrop : function(target, e, id){
23333 onValidDrop : function(target, e, id){
23335 if(this.afterValidDrop){
23337 * An empty function by default, but provided so that you can perform a custom action
23338 * after a valid drop has occurred by providing an implementation.
23339 * @param {Object} target The target DD
23340 * @param {Event} e The event object
23341 * @param {String} id The id of the dropped element
23342 * @method afterInvalidDrop
23344 this.afterValidDrop(target, e, id);
23349 getRepairXY : function(e, data){
23350 return this.el.getXY();
23354 onInvalidDrop : function(target, e, id){
23355 this.beforeInvalidDrop(target, e, id);
23356 if(this.cachedTarget){
23357 if(this.cachedTarget.isNotifyTarget){
23358 this.cachedTarget.notifyOut(this, e, this.dragData);
23360 this.cacheTarget = null;
23362 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
23364 if(this.afterInvalidDrop){
23366 * An empty function by default, but provided so that you can perform a custom action
23367 * after an invalid drop has occurred by providing an implementation.
23368 * @param {Event} e The event object
23369 * @param {String} id The id of the dropped element
23370 * @method afterInvalidDrop
23372 this.afterInvalidDrop(e, id);
23377 afterRepair : function(){
23379 this.el.highlight(this.hlColor || "c3daf9");
23381 this.dragging = false;
23385 * An empty function by default, but provided so that you can perform a custom action after an invalid
23386 * drop has occurred.
23387 * @param {Roo.dd.DragDrop} target The drop target
23388 * @param {Event} e The event object
23389 * @param {String} id The id of the dragged element
23390 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
23392 beforeInvalidDrop : function(target, e, id){
23397 handleMouseDown : function(e){
23398 if(this.dragging) {
23401 var data = this.getDragData(e);
23402 if(data && this.onBeforeDrag(data, e) !== false){
23403 this.dragData = data;
23405 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
23410 * An empty function by default, but provided so that you can perform a custom action before the initial
23411 * drag event begins and optionally cancel it.
23412 * @param {Object} data An object containing arbitrary data to be shared with drop targets
23413 * @param {Event} e The event object
23414 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
23416 onBeforeDrag : function(data, e){
23421 * An empty function by default, but provided so that you can perform a custom action once the initial
23422 * drag event has begun. The drag cannot be canceled from this function.
23423 * @param {Number} x The x position of the click on the dragged object
23424 * @param {Number} y The y position of the click on the dragged object
23426 onStartDrag : Roo.emptyFn,
23428 // private - YUI override
23429 startDrag : function(x, y){
23430 this.proxy.reset();
23431 this.dragging = true;
23432 this.proxy.update("");
23433 this.onInitDrag(x, y);
23438 onInitDrag : function(x, y){
23439 var clone = this.el.dom.cloneNode(true);
23440 clone.id = Roo.id(); // prevent duplicate ids
23441 this.proxy.update(clone);
23442 this.onStartDrag(x, y);
23447 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
23448 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
23450 getProxy : function(){
23455 * Hides the drag source's {@link Roo.dd.StatusProxy}
23457 hideProxy : function(){
23459 this.proxy.reset(true);
23460 this.dragging = false;
23464 triggerCacheRefresh : function(){
23465 Roo.dd.DDM.refreshCache(this.groups);
23468 // private - override to prevent hiding
23469 b4EndDrag: function(e) {
23472 // private - override to prevent moving
23473 endDrag : function(e){
23474 this.onEndDrag(this.dragData, e);
23478 onEndDrag : function(data, e){
23481 // private - pin to cursor
23482 autoOffset : function(x, y) {
23483 this.setDelta(-12, -20);
23487 * Ext JS Library 1.1.1
23488 * Copyright(c) 2006-2007, Ext JS, LLC.
23490 * Originally Released Under LGPL - original licence link has changed is not relivant.
23493 * <script type="text/javascript">
23498 * @class Roo.dd.DropTarget
23499 * @extends Roo.dd.DDTarget
23500 * A simple class that provides the basic implementation needed to make any element a drop target that can have
23501 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
23503 * @param {String/HTMLElement/Element} el The container element
23504 * @param {Object} config
23506 Roo.dd.DropTarget = function(el, config){
23507 this.el = Roo.get(el);
23509 var listeners = false; ;
23510 if (config && config.listeners) {
23511 listeners= config.listeners;
23512 delete config.listeners;
23514 Roo.apply(this, config);
23516 if(this.containerScroll){
23517 Roo.dd.ScrollManager.register(this.el);
23521 * @scope Roo.dd.DropTarget
23526 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
23527 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
23528 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
23530 * IMPORTANT : it should set this.valid to true|false
23532 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
23533 * @param {Event} e The event
23534 * @param {Object} data An object containing arbitrary data supplied by the drag source
23540 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
23541 * This method will be called on every mouse movement while the drag source is over the drop target.
23542 * This default implementation simply returns the dropAllowed config value.
23544 * IMPORTANT : it should set this.valid to true|false
23546 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
23547 * @param {Event} e The event
23548 * @param {Object} data An object containing arbitrary data supplied by the drag source
23554 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
23555 * out of the target without dropping. This default implementation simply removes the CSS class specified by
23556 * overClass (if any) from the drop element.
23559 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
23560 * @param {Event} e The event
23561 * @param {Object} data An object containing arbitrary data supplied by the drag source
23567 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
23568 * been dropped on it. This method has no default implementation and returns false, so you must provide an
23569 * implementation that does something to process the drop event and returns true so that the drag source's
23570 * repair action does not run.
23572 * IMPORTANT : it should set this.success
23574 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
23575 * @param {Event} e The event
23576 * @param {Object} data An object containing arbitrary data supplied by the drag source
23582 Roo.dd.DropTarget.superclass.constructor.call( this,
23584 this.ddGroup || this.group,
23587 listeners : listeners || {}
23595 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
23597 * @cfg {String} overClass
23598 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
23601 * @cfg {String} ddGroup
23602 * The drag drop group to handle drop events for
23606 * @cfg {String} dropAllowed
23607 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
23609 dropAllowed : "x-dd-drop-ok",
23611 * @cfg {String} dropNotAllowed
23612 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
23614 dropNotAllowed : "x-dd-drop-nodrop",
23616 * @cfg {boolean} success
23617 * set this after drop listener..
23621 * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
23622 * if the drop point is valid for over/enter..
23629 isNotifyTarget : true,
23634 notifyEnter : function(dd, e, data)
23637 this.fireEvent('enter', dd, e, data);
23638 if(this.overClass){
23639 this.el.addClass(this.overClass);
23641 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
23642 this.valid ? this.dropAllowed : this.dropNotAllowed
23649 notifyOver : function(dd, e, data)
23652 this.fireEvent('over', dd, e, data);
23653 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
23654 this.valid ? this.dropAllowed : this.dropNotAllowed
23661 notifyOut : function(dd, e, data)
23663 this.fireEvent('out', dd, e, data);
23664 if(this.overClass){
23665 this.el.removeClass(this.overClass);
23672 notifyDrop : function(dd, e, data)
23674 this.success = false;
23675 this.fireEvent('drop', dd, e, data);
23676 return this.success;
23680 * Ext JS Library 1.1.1
23681 * Copyright(c) 2006-2007, Ext JS, LLC.
23683 * Originally Released Under LGPL - original licence link has changed is not relivant.
23686 * <script type="text/javascript">
23691 * @class Roo.dd.DragZone
23692 * @extends Roo.dd.DragSource
23693 * This class provides a container DD instance that proxies for multiple child node sources.<br />
23694 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
23696 * @param {String/HTMLElement/Element} el The container element
23697 * @param {Object} config
23699 Roo.dd.DragZone = function(el, config){
23700 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
23701 if(this.containerScroll){
23702 Roo.dd.ScrollManager.register(this.el);
23706 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
23708 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
23709 * for auto scrolling during drag operations.
23712 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
23713 * method after a failed drop (defaults to "c3daf9" - light blue)
23717 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
23718 * for a valid target to drag based on the mouse down. Override this method
23719 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
23720 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
23721 * @param {EventObject} e The mouse down event
23722 * @return {Object} The dragData
23724 getDragData : function(e){
23725 return Roo.dd.Registry.getHandleFromEvent(e);
23729 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
23730 * this.dragData.ddel
23731 * @param {Number} x The x position of the click on the dragged object
23732 * @param {Number} y The y position of the click on the dragged object
23733 * @return {Boolean} true to continue the drag, false to cancel
23735 onInitDrag : function(x, y){
23736 this.proxy.update(this.dragData.ddel.cloneNode(true));
23737 this.onStartDrag(x, y);
23742 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
23744 afterRepair : function(){
23746 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
23748 this.dragging = false;
23752 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
23753 * the XY of this.dragData.ddel
23754 * @param {EventObject} e The mouse up event
23755 * @return {Array} The xy location (e.g. [100, 200])
23757 getRepairXY : function(e){
23758 return Roo.Element.fly(this.dragData.ddel).getXY();
23762 * Ext JS Library 1.1.1
23763 * Copyright(c) 2006-2007, Ext JS, LLC.
23765 * Originally Released Under LGPL - original licence link has changed is not relivant.
23768 * <script type="text/javascript">
23771 * @class Roo.dd.DropZone
23772 * @extends Roo.dd.DropTarget
23773 * This class provides a container DD instance that proxies for multiple child node targets.<br />
23774 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
23776 * @param {String/HTMLElement/Element} el The container element
23777 * @param {Object} config
23779 Roo.dd.DropZone = function(el, config){
23780 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
23783 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
23785 * Returns a custom data object associated with the DOM node that is the target of the event. By default
23786 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
23787 * provide your own custom lookup.
23788 * @param {Event} e The event
23789 * @return {Object} data The custom data
23791 getTargetFromEvent : function(e){
23792 return Roo.dd.Registry.getTargetFromEvent(e);
23796 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
23797 * that it has registered. This method has no default implementation and should be overridden to provide
23798 * node-specific processing if necessary.
23799 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
23800 * {@link #getTargetFromEvent} for this node)
23801 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23802 * @param {Event} e The event
23803 * @param {Object} data An object containing arbitrary data supplied by the drag source
23805 onNodeEnter : function(n, dd, e, data){
23810 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
23811 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
23812 * overridden to provide the proper feedback.
23813 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
23814 * {@link #getTargetFromEvent} for this node)
23815 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23816 * @param {Event} e The event
23817 * @param {Object} data An object containing arbitrary data supplied by the drag source
23818 * @return {String} status The CSS class that communicates the drop status back to the source so that the
23819 * underlying {@link Roo.dd.StatusProxy} can be updated
23821 onNodeOver : function(n, dd, e, data){
23822 return this.dropAllowed;
23826 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
23827 * the drop node without dropping. This method has no default implementation and should be overridden to provide
23828 * node-specific processing if necessary.
23829 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
23830 * {@link #getTargetFromEvent} for this node)
23831 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23832 * @param {Event} e The event
23833 * @param {Object} data An object containing arbitrary data supplied by the drag source
23835 onNodeOut : function(n, dd, e, data){
23840 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
23841 * the drop node. The default implementation returns false, so it should be overridden to provide the
23842 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
23843 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
23844 * {@link #getTargetFromEvent} for this node)
23845 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23846 * @param {Event} e The event
23847 * @param {Object} data An object containing arbitrary data supplied by the drag source
23848 * @return {Boolean} True if the drop was valid, else false
23850 onNodeDrop : function(n, dd, e, data){
23855 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
23856 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
23857 * it should be overridden to provide the proper feedback if necessary.
23858 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23859 * @param {Event} e The event
23860 * @param {Object} data An object containing arbitrary data supplied by the drag source
23861 * @return {String} status The CSS class that communicates the drop status back to the source so that the
23862 * underlying {@link Roo.dd.StatusProxy} can be updated
23864 onContainerOver : function(dd, e, data){
23865 return this.dropNotAllowed;
23869 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
23870 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
23871 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
23872 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
23873 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23874 * @param {Event} e The event
23875 * @param {Object} data An object containing arbitrary data supplied by the drag source
23876 * @return {Boolean} True if the drop was valid, else false
23878 onContainerDrop : function(dd, e, data){
23883 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
23884 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
23885 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
23886 * you should override this method and provide a custom implementation.
23887 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23888 * @param {Event} e The event
23889 * @param {Object} data An object containing arbitrary data supplied by the drag source
23890 * @return {String} status The CSS class that communicates the drop status back to the source so that the
23891 * underlying {@link Roo.dd.StatusProxy} can be updated
23893 notifyEnter : function(dd, e, data){
23894 return this.dropNotAllowed;
23898 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
23899 * This method will be called on every mouse movement while the drag source is over the drop zone.
23900 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
23901 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
23902 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
23903 * registered node, it will call {@link #onContainerOver}.
23904 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23905 * @param {Event} e The event
23906 * @param {Object} data An object containing arbitrary data supplied by the drag source
23907 * @return {String} status The CSS class that communicates the drop status back to the source so that the
23908 * underlying {@link Roo.dd.StatusProxy} can be updated
23910 notifyOver : function(dd, e, data){
23911 var n = this.getTargetFromEvent(e);
23912 if(!n){ // not over valid drop target
23913 if(this.lastOverNode){
23914 this.onNodeOut(this.lastOverNode, dd, e, data);
23915 this.lastOverNode = null;
23917 return this.onContainerOver(dd, e, data);
23919 if(this.lastOverNode != n){
23920 if(this.lastOverNode){
23921 this.onNodeOut(this.lastOverNode, dd, e, data);
23923 this.onNodeEnter(n, dd, e, data);
23924 this.lastOverNode = n;
23926 return this.onNodeOver(n, dd, e, data);
23930 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
23931 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
23932 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
23933 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
23934 * @param {Event} e The event
23935 * @param {Object} data An object containing arbitrary data supplied by the drag zone
23937 notifyOut : function(dd, e, data){
23938 if(this.lastOverNode){
23939 this.onNodeOut(this.lastOverNode, dd, e, data);
23940 this.lastOverNode = null;
23945 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
23946 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
23947 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
23948 * otherwise it will call {@link #onContainerDrop}.
23949 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23950 * @param {Event} e The event
23951 * @param {Object} data An object containing arbitrary data supplied by the drag source
23952 * @return {Boolean} True if the drop was valid, else false
23954 notifyDrop : function(dd, e, data){
23955 if(this.lastOverNode){
23956 this.onNodeOut(this.lastOverNode, dd, e, data);
23957 this.lastOverNode = null;
23959 var n = this.getTargetFromEvent(e);
23961 this.onNodeDrop(n, dd, e, data) :
23962 this.onContainerDrop(dd, e, data);
23966 triggerCacheRefresh : function(){
23967 Roo.dd.DDM.refreshCache(this.groups);
23971 * Ext JS Library 1.1.1
23972 * Copyright(c) 2006-2007, Ext JS, LLC.
23974 * Originally Released Under LGPL - original licence link has changed is not relivant.
23977 * <script type="text/javascript">
23982 * @class Roo.data.SortTypes
23984 * Defines the default sorting (casting?) comparison functions used when sorting data.
23986 Roo.data.SortTypes = {
23988 * Default sort that does nothing
23989 * @param {Mixed} s The value being converted
23990 * @return {Mixed} The comparison value
23992 none : function(s){
23997 * The regular expression used to strip tags
24001 stripTagsRE : /<\/?[^>]+>/gi,
24004 * Strips all HTML tags to sort on text only
24005 * @param {Mixed} s The value being converted
24006 * @return {String} The comparison value
24008 asText : function(s){
24009 return String(s).replace(this.stripTagsRE, "");
24013 * Strips all HTML tags to sort on text only - Case insensitive
24014 * @param {Mixed} s The value being converted
24015 * @return {String} The comparison value
24017 asUCText : function(s){
24018 return String(s).toUpperCase().replace(this.stripTagsRE, "");
24022 * Case insensitive string
24023 * @param {Mixed} s The value being converted
24024 * @return {String} The comparison value
24026 asUCString : function(s) {
24027 return String(s).toUpperCase();
24032 * @param {Mixed} s The value being converted
24033 * @return {Number} The comparison value
24035 asDate : function(s) {
24039 if(s instanceof Date){
24040 return s.getTime();
24042 return Date.parse(String(s));
24047 * @param {Mixed} s The value being converted
24048 * @return {Float} The comparison value
24050 asFloat : function(s) {
24051 var val = parseFloat(String(s).replace(/,/g, ""));
24060 * @param {Mixed} s The value being converted
24061 * @return {Number} The comparison value
24063 asInt : function(s) {
24064 var val = parseInt(String(s).replace(/,/g, ""));
24072 * Ext JS Library 1.1.1
24073 * Copyright(c) 2006-2007, Ext JS, LLC.
24075 * Originally Released Under LGPL - original licence link has changed is not relivant.
24078 * <script type="text/javascript">
24082 * @class Roo.data.Record
24083 * Instances of this class encapsulate both record <em>definition</em> information, and record
24084 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
24085 * to access Records cached in an {@link Roo.data.Store} object.<br>
24087 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
24088 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
24091 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
24093 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
24094 * {@link #create}. The parameters are the same.
24095 * @param {Array} data An associative Array of data values keyed by the field name.
24096 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
24097 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
24098 * not specified an integer id is generated.
24100 Roo.data.Record = function(data, id){
24101 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
24106 * Generate a constructor for a specific record layout.
24107 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
24108 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
24109 * Each field definition object may contain the following properties: <ul>
24110 * <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,
24111 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
24112 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
24113 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
24114 * is being used, then this is a string containing the javascript expression to reference the data relative to
24115 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
24116 * to the data item relative to the record element. If the mapping expression is the same as the field name,
24117 * this may be omitted.</p></li>
24118 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
24119 * <ul><li>auto (Default, implies no conversion)</li>
24124 * <li>date</li></ul></p></li>
24125 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
24126 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
24127 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
24128 * by the Reader into an object that will be stored in the Record. It is passed the
24129 * following parameters:<ul>
24130 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
24132 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
24134 * <br>usage:<br><pre><code>
24135 var TopicRecord = Roo.data.Record.create(
24136 {name: 'title', mapping: 'topic_title'},
24137 {name: 'author', mapping: 'username'},
24138 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
24139 {name: 'lastPost', mapping: 'post_time', type: 'date'},
24140 {name: 'lastPoster', mapping: 'user2'},
24141 {name: 'excerpt', mapping: 'post_text'}
24144 var myNewRecord = new TopicRecord({
24145 title: 'Do my job please',
24148 lastPost: new Date(),
24149 lastPoster: 'Animal',
24150 excerpt: 'No way dude!'
24152 myStore.add(myNewRecord);
24157 Roo.data.Record.create = function(o){
24158 var f = function(){
24159 f.superclass.constructor.apply(this, arguments);
24161 Roo.extend(f, Roo.data.Record);
24162 var p = f.prototype;
24163 p.fields = new Roo.util.MixedCollection(false, function(field){
24166 for(var i = 0, len = o.length; i < len; i++){
24167 p.fields.add(new Roo.data.Field(o[i]));
24169 f.getField = function(name){
24170 return p.fields.get(name);
24175 Roo.data.Record.AUTO_ID = 1000;
24176 Roo.data.Record.EDIT = 'edit';
24177 Roo.data.Record.REJECT = 'reject';
24178 Roo.data.Record.COMMIT = 'commit';
24180 Roo.data.Record.prototype = {
24182 * Readonly flag - true if this record has been modified.
24191 join : function(store){
24192 this.store = store;
24196 * Set the named field to the specified value.
24197 * @param {String} name The name of the field to set.
24198 * @param {Object} value The value to set the field to.
24200 set : function(name, value){
24201 if(this.data[name] == value){
24205 if(!this.modified){
24206 this.modified = {};
24208 if(typeof this.modified[name] == 'undefined'){
24209 this.modified[name] = this.data[name];
24211 this.data[name] = value;
24212 if(!this.editing && this.store){
24213 this.store.afterEdit(this);
24218 * Get the value of the named field.
24219 * @param {String} name The name of the field to get the value of.
24220 * @return {Object} The value of the field.
24222 get : function(name){
24223 return this.data[name];
24227 beginEdit : function(){
24228 this.editing = true;
24229 this.modified = {};
24233 cancelEdit : function(){
24234 this.editing = false;
24235 delete this.modified;
24239 endEdit : function(){
24240 this.editing = false;
24241 if(this.dirty && this.store){
24242 this.store.afterEdit(this);
24247 * Usually called by the {@link Roo.data.Store} which owns the Record.
24248 * Rejects all changes made to the Record since either creation, or the last commit operation.
24249 * Modified fields are reverted to their original values.
24251 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
24252 * of reject operations.
24254 reject : function(){
24255 var m = this.modified;
24257 if(typeof m[n] != "function"){
24258 this.data[n] = m[n];
24261 this.dirty = false;
24262 delete this.modified;
24263 this.editing = false;
24265 this.store.afterReject(this);
24270 * Usually called by the {@link Roo.data.Store} which owns the Record.
24271 * Commits all changes made to the Record since either creation, or the last commit operation.
24273 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
24274 * of commit operations.
24276 commit : function(){
24277 this.dirty = false;
24278 delete this.modified;
24279 this.editing = false;
24281 this.store.afterCommit(this);
24286 hasError : function(){
24287 return this.error != null;
24291 clearError : function(){
24296 * Creates a copy of this record.
24297 * @param {String} id (optional) A new record id if you don't want to use this record's id
24300 copy : function(newId) {
24301 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
24305 * Ext JS Library 1.1.1
24306 * Copyright(c) 2006-2007, Ext JS, LLC.
24308 * Originally Released Under LGPL - original licence link has changed is not relivant.
24311 * <script type="text/javascript">
24317 * @class Roo.data.Store
24318 * @extends Roo.util.Observable
24319 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
24320 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
24322 * 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
24323 * has no knowledge of the format of the data returned by the Proxy.<br>
24325 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
24326 * instances from the data object. These records are cached and made available through accessor functions.
24328 * Creates a new Store.
24329 * @param {Object} config A config object containing the objects needed for the Store to access data,
24330 * and read the data into Records.
24332 Roo.data.Store = function(config){
24333 this.data = new Roo.util.MixedCollection(false);
24334 this.data.getKey = function(o){
24337 this.baseParams = {};
24339 this.paramNames = {
24344 "multisort" : "_multisort"
24347 if(config && config.data){
24348 this.inlineData = config.data;
24349 delete config.data;
24352 Roo.apply(this, config);
24354 if(this.reader){ // reader passed
24355 this.reader = Roo.factory(this.reader, Roo.data);
24356 this.reader.xmodule = this.xmodule || false;
24357 if(!this.recordType){
24358 this.recordType = this.reader.recordType;
24360 if(this.reader.onMetaChange){
24361 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
24365 if(this.recordType){
24366 this.fields = this.recordType.prototype.fields;
24368 this.modified = [];
24372 * @event datachanged
24373 * Fires when the data cache has changed, and a widget which is using this Store
24374 * as a Record cache should refresh its view.
24375 * @param {Store} this
24377 datachanged : true,
24379 * @event metachange
24380 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
24381 * @param {Store} this
24382 * @param {Object} meta The JSON metadata
24387 * Fires when Records have been added to the Store
24388 * @param {Store} this
24389 * @param {Roo.data.Record[]} records The array of Records added
24390 * @param {Number} index The index at which the record(s) were added
24395 * Fires when a Record has been removed from the Store
24396 * @param {Store} this
24397 * @param {Roo.data.Record} record The Record that was removed
24398 * @param {Number} index The index at which the record was removed
24403 * Fires when a Record has been updated
24404 * @param {Store} this
24405 * @param {Roo.data.Record} record The Record that was updated
24406 * @param {String} operation The update operation being performed. Value may be one of:
24408 Roo.data.Record.EDIT
24409 Roo.data.Record.REJECT
24410 Roo.data.Record.COMMIT
24416 * Fires when the data cache has been cleared.
24417 * @param {Store} this
24421 * @event beforeload
24422 * Fires before a request is made for a new data object. If the beforeload handler returns false
24423 * the load action will be canceled.
24424 * @param {Store} this
24425 * @param {Object} options The loading options that were specified (see {@link #load} for details)
24429 * @event beforeloadadd
24430 * Fires after a new set of Records has been loaded.
24431 * @param {Store} this
24432 * @param {Roo.data.Record[]} records The Records that were loaded
24433 * @param {Object} options The loading options that were specified (see {@link #load} for details)
24435 beforeloadadd : true,
24438 * Fires after a new set of Records has been loaded, before they are added to the store.
24439 * @param {Store} this
24440 * @param {Roo.data.Record[]} records The Records that were loaded
24441 * @param {Object} options The loading options that were specified (see {@link #load} for details)
24442 * @params {Object} return from reader
24446 * @event loadexception
24447 * Fires if an exception occurs in the Proxy during loading.
24448 * Called with the signature of the Proxy's "loadexception" event.
24449 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
24452 * @param {Object} return from JsonData.reader() - success, totalRecords, records
24453 * @param {Object} load options
24454 * @param {Object} jsonData from your request (normally this contains the Exception)
24456 loadexception : true
24460 this.proxy = Roo.factory(this.proxy, Roo.data);
24461 this.proxy.xmodule = this.xmodule || false;
24462 this.relayEvents(this.proxy, ["loadexception"]);
24464 this.sortToggle = {};
24465 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
24467 Roo.data.Store.superclass.constructor.call(this);
24469 if(this.inlineData){
24470 this.loadData(this.inlineData);
24471 delete this.inlineData;
24475 Roo.extend(Roo.data.Store, Roo.util.Observable, {
24477 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
24478 * without a remote query - used by combo/forms at present.
24482 * @cfg {Roo.data.DataProxy} proxy [required] The Proxy object which provides access to a data object.
24485 * @cfg {Array} data Inline data to be loaded when the store is initialized.
24488 * @cfg {Roo.data.DataReader} reader [required] The Reader object which processes the data object and returns
24489 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
24492 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
24493 * on any HTTP request
24496 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
24499 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
24503 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
24504 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
24506 remoteSort : false,
24509 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
24510 * loaded or when a record is removed. (defaults to false).
24512 pruneModifiedRecords : false,
24515 lastOptions : null,
24518 * Add Records to the Store and fires the add event.
24519 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
24521 add : function(records){
24522 records = [].concat(records);
24523 for(var i = 0, len = records.length; i < len; i++){
24524 records[i].join(this);
24526 var index = this.data.length;
24527 this.data.addAll(records);
24528 this.fireEvent("add", this, records, index);
24532 * Remove a Record from the Store and fires the remove event.
24533 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
24535 remove : function(record){
24536 var index = this.data.indexOf(record);
24537 this.data.removeAt(index);
24539 if(this.pruneModifiedRecords){
24540 this.modified.remove(record);
24542 this.fireEvent("remove", this, record, index);
24546 * Remove all Records from the Store and fires the clear event.
24548 removeAll : function(){
24550 if(this.pruneModifiedRecords){
24551 this.modified = [];
24553 this.fireEvent("clear", this);
24557 * Inserts Records to the Store at the given index and fires the add event.
24558 * @param {Number} index The start index at which to insert the passed Records.
24559 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
24561 insert : function(index, records){
24562 records = [].concat(records);
24563 for(var i = 0, len = records.length; i < len; i++){
24564 this.data.insert(index, records[i]);
24565 records[i].join(this);
24567 this.fireEvent("add", this, records, index);
24571 * Get the index within the cache of the passed Record.
24572 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
24573 * @return {Number} The index of the passed Record. Returns -1 if not found.
24575 indexOf : function(record){
24576 return this.data.indexOf(record);
24580 * Get the index within the cache of the Record with the passed id.
24581 * @param {String} id The id of the Record to find.
24582 * @return {Number} The index of the Record. Returns -1 if not found.
24584 indexOfId : function(id){
24585 return this.data.indexOfKey(id);
24589 * Get the Record with the specified id.
24590 * @param {String} id The id of the Record to find.
24591 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
24593 getById : function(id){
24594 return this.data.key(id);
24598 * Get the Record at the specified index.
24599 * @param {Number} index The index of the Record to find.
24600 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
24602 getAt : function(index){
24603 return this.data.itemAt(index);
24607 * Returns a range of Records between specified indices.
24608 * @param {Number} startIndex (optional) The starting index (defaults to 0)
24609 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
24610 * @return {Roo.data.Record[]} An array of Records
24612 getRange : function(start, end){
24613 return this.data.getRange(start, end);
24617 storeOptions : function(o){
24618 o = Roo.apply({}, o);
24621 this.lastOptions = o;
24625 * Loads the Record cache from the configured Proxy using the configured Reader.
24627 * If using remote paging, then the first load call must specify the <em>start</em>
24628 * and <em>limit</em> properties in the options.params property to establish the initial
24629 * position within the dataset, and the number of Records to cache on each read from the Proxy.
24631 * <strong>It is important to note that for remote data sources, loading is asynchronous,
24632 * and this call will return before the new data has been loaded. Perform any post-processing
24633 * in a callback function, or in a "load" event handler.</strong>
24635 * @param {Object} options An object containing properties which control loading options:<ul>
24636 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
24637 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
24638 * passed the following arguments:<ul>
24639 * <li>r : Roo.data.Record[]</li>
24640 * <li>options: Options object from the load call</li>
24641 * <li>success: Boolean success indicator</li></ul></li>
24642 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
24643 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
24646 load : function(options){
24647 options = options || {};
24648 if(this.fireEvent("beforeload", this, options) !== false){
24649 this.storeOptions(options);
24650 var p = Roo.apply(options.params || {}, this.baseParams);
24651 // if meta was not loaded from remote source.. try requesting it.
24652 if (!this.reader.metaFromRemote) {
24653 p._requestMeta = 1;
24655 if(this.sortInfo && this.remoteSort){
24656 var pn = this.paramNames;
24657 p[pn["sort"]] = this.sortInfo.field;
24658 p[pn["dir"]] = this.sortInfo.direction;
24660 if (this.multiSort) {
24661 var pn = this.paramNames;
24662 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
24665 this.proxy.load(p, this.reader, this.loadRecords, this, options);
24670 * Reloads the Record cache from the configured Proxy using the configured Reader and
24671 * the options from the last load operation performed.
24672 * @param {Object} options (optional) An object containing properties which may override the options
24673 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
24674 * the most recently used options are reused).
24676 reload : function(options){
24677 this.load(Roo.applyIf(options||{}, this.lastOptions));
24681 // Called as a callback by the Reader during a load operation.
24682 loadRecords : function(o, options, success){
24685 if(success !== false){
24686 this.fireEvent("load", this, [], options, o);
24688 if(options.callback){
24689 options.callback.call(options.scope || this, [], options, false);
24693 // if data returned failure - throw an exception.
24694 if (o.success === false) {
24695 // show a message if no listener is registered.
24696 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
24697 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
24699 // loadmask wil be hooked into this..
24700 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
24703 var r = o.records, t = o.totalRecords || r.length;
24705 this.fireEvent("beforeloadadd", this, r, options, o);
24707 if(!options || options.add !== true){
24708 if(this.pruneModifiedRecords){
24709 this.modified = [];
24711 for(var i = 0, len = r.length; i < len; i++){
24715 this.data = this.snapshot;
24716 delete this.snapshot;
24719 this.data.addAll(r);
24720 this.totalLength = t;
24722 this.fireEvent("datachanged", this);
24724 this.totalLength = Math.max(t, this.data.length+r.length);
24728 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
24730 var e = new Roo.data.Record({});
24732 e.set(this.parent.displayField, this.parent.emptyTitle);
24733 e.set(this.parent.valueField, '');
24738 this.fireEvent("load", this, r, options, o);
24739 if(options.callback){
24740 options.callback.call(options.scope || this, r, options, true);
24746 * Loads data from a passed data block. A Reader which understands the format of the data
24747 * must have been configured in the constructor.
24748 * @param {Object} data The data block from which to read the Records. The format of the data expected
24749 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
24750 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
24752 loadData : function(o, append){
24753 var r = this.reader.readRecords(o);
24754 this.loadRecords(r, {add: append}, true);
24758 * using 'cn' the nested child reader read the child array into it's child stores.
24759 * @param {Object} rec The record with a 'children array
24761 loadDataFromChildren : function(rec)
24763 this.loadData(this.reader.toLoadData(rec));
24768 * Gets the number of cached records.
24770 * <em>If using paging, this may not be the total size of the dataset. If the data object
24771 * used by the Reader contains the dataset size, then the getTotalCount() function returns
24772 * the data set size</em>
24774 getCount : function(){
24775 return this.data.length || 0;
24779 * Gets the total number of records in the dataset as returned by the server.
24781 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
24782 * the dataset size</em>
24784 getTotalCount : function(){
24785 return this.totalLength || 0;
24789 * Returns the sort state of the Store as an object with two properties:
24791 field {String} The name of the field by which the Records are sorted
24792 direction {String} The sort order, "ASC" or "DESC"
24795 getSortState : function(){
24796 return this.sortInfo;
24800 applySort : function(){
24801 if(this.sortInfo && !this.remoteSort){
24802 var s = this.sortInfo, f = s.field;
24803 var st = this.fields.get(f).sortType;
24804 var fn = function(r1, r2){
24805 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
24806 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
24808 this.data.sort(s.direction, fn);
24809 if(this.snapshot && this.snapshot != this.data){
24810 this.snapshot.sort(s.direction, fn);
24816 * Sets the default sort column and order to be used by the next load operation.
24817 * @param {String} fieldName The name of the field to sort by.
24818 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
24820 setDefaultSort : function(field, dir){
24821 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
24825 * Sort the Records.
24826 * If remote sorting is used, the sort is performed on the server, and the cache is
24827 * reloaded. If local sorting is used, the cache is sorted internally.
24828 * @param {String} fieldName The name of the field to sort by.
24829 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
24831 sort : function(fieldName, dir){
24832 var f = this.fields.get(fieldName);
24834 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
24836 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
24837 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
24842 this.sortToggle[f.name] = dir;
24843 this.sortInfo = {field: f.name, direction: dir};
24844 if(!this.remoteSort){
24846 this.fireEvent("datachanged", this);
24848 this.load(this.lastOptions);
24853 * Calls the specified function for each of the Records in the cache.
24854 * @param {Function} fn The function to call. The Record is passed as the first parameter.
24855 * Returning <em>false</em> aborts and exits the iteration.
24856 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
24858 each : function(fn, scope){
24859 this.data.each(fn, scope);
24863 * Gets all records modified since the last commit. Modified records are persisted across load operations
24864 * (e.g., during paging).
24865 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
24867 getModifiedRecords : function(){
24868 return this.modified;
24872 createFilterFn : function(property, value, anyMatch){
24873 if(!value.exec){ // not a regex
24874 value = String(value);
24875 if(value.length == 0){
24878 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
24880 return function(r){
24881 return value.test(r.data[property]);
24886 * Sums the value of <i>property</i> for each record between start and end and returns the result.
24887 * @param {String} property A field on your records
24888 * @param {Number} start The record index to start at (defaults to 0)
24889 * @param {Number} end The last record index to include (defaults to length - 1)
24890 * @return {Number} The sum
24892 sum : function(property, start, end){
24893 var rs = this.data.items, v = 0;
24894 start = start || 0;
24895 end = (end || end === 0) ? end : rs.length-1;
24897 for(var i = start; i <= end; i++){
24898 v += (rs[i].data[property] || 0);
24904 * Filter the records by a specified property.
24905 * @param {String} field A field on your records
24906 * @param {String/RegExp} value Either a string that the field
24907 * should start with or a RegExp to test against the field
24908 * @param {Boolean} anyMatch True to match any part not just the beginning
24910 filter : function(property, value, anyMatch){
24911 var fn = this.createFilterFn(property, value, anyMatch);
24912 return fn ? this.filterBy(fn) : this.clearFilter();
24916 * Filter by a function. The specified function will be called with each
24917 * record in this data source. If the function returns true the record is included,
24918 * otherwise it is filtered.
24919 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
24920 * @param {Object} scope (optional) The scope of the function (defaults to this)
24922 filterBy : function(fn, scope){
24923 this.snapshot = this.snapshot || this.data;
24924 this.data = this.queryBy(fn, scope||this);
24925 this.fireEvent("datachanged", this);
24929 * Query the records by a specified property.
24930 * @param {String} field A field on your records
24931 * @param {String/RegExp} value Either a string that the field
24932 * should start with or a RegExp to test against the field
24933 * @param {Boolean} anyMatch True to match any part not just the beginning
24934 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
24936 query : function(property, value, anyMatch){
24937 var fn = this.createFilterFn(property, value, anyMatch);
24938 return fn ? this.queryBy(fn) : this.data.clone();
24942 * Query by a function. The specified function will be called with each
24943 * record in this data source. If the function returns true the record is included
24945 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
24946 * @param {Object} scope (optional) The scope of the function (defaults to this)
24947 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
24949 queryBy : function(fn, scope){
24950 var data = this.snapshot || this.data;
24951 return data.filterBy(fn, scope||this);
24955 * Collects unique values for a particular dataIndex from this store.
24956 * @param {String} dataIndex The property to collect
24957 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
24958 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
24959 * @return {Array} An array of the unique values
24961 collect : function(dataIndex, allowNull, bypassFilter){
24962 var d = (bypassFilter === true && this.snapshot) ?
24963 this.snapshot.items : this.data.items;
24964 var v, sv, r = [], l = {};
24965 for(var i = 0, len = d.length; i < len; i++){
24966 v = d[i].data[dataIndex];
24968 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
24977 * Revert to a view of the Record cache with no filtering applied.
24978 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
24980 clearFilter : function(suppressEvent){
24981 if(this.snapshot && this.snapshot != this.data){
24982 this.data = this.snapshot;
24983 delete this.snapshot;
24984 if(suppressEvent !== true){
24985 this.fireEvent("datachanged", this);
24991 afterEdit : function(record){
24992 if(this.modified.indexOf(record) == -1){
24993 this.modified.push(record);
24995 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
24999 afterReject : function(record){
25000 this.modified.remove(record);
25001 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
25005 afterCommit : function(record){
25006 this.modified.remove(record);
25007 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
25011 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
25012 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
25014 commitChanges : function(){
25015 var m = this.modified.slice(0);
25016 this.modified = [];
25017 for(var i = 0, len = m.length; i < len; i++){
25023 * Cancel outstanding changes on all changed records.
25025 rejectChanges : function(){
25026 var m = this.modified.slice(0);
25027 this.modified = [];
25028 for(var i = 0, len = m.length; i < len; i++){
25033 onMetaChange : function(meta, rtype, o){
25034 this.recordType = rtype;
25035 this.fields = rtype.prototype.fields;
25036 delete this.snapshot;
25037 this.sortInfo = meta.sortInfo || this.sortInfo;
25038 this.modified = [];
25039 this.fireEvent('metachange', this, this.reader.meta);
25042 moveIndex : function(data, type)
25044 var index = this.indexOf(data);
25046 var newIndex = index + type;
25050 this.insert(newIndex, data);
25055 * Ext JS Library 1.1.1
25056 * Copyright(c) 2006-2007, Ext JS, LLC.
25058 * Originally Released Under LGPL - original licence link has changed is not relivant.
25061 * <script type="text/javascript">
25065 * @class Roo.data.SimpleStore
25066 * @extends Roo.data.Store
25067 * Small helper class to make creating Stores from Array data easier.
25068 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
25069 * @cfg {Array} fields An array of field definition objects, or field name strings.
25070 * @cfg {Object} an existing reader (eg. copied from another store)
25071 * @cfg {Array} data The multi-dimensional array of data
25072 * @cfg {Roo.data.DataProxy} proxy [not-required]
25073 * @cfg {Roo.data.Reader} reader [not-required]
25075 * @param {Object} config
25077 Roo.data.SimpleStore = function(config)
25079 Roo.data.SimpleStore.superclass.constructor.call(this, {
25081 reader: typeof(config.reader) != 'undefined' ? config.reader : new Roo.data.ArrayReader({
25084 Roo.data.Record.create(config.fields)
25086 proxy : new Roo.data.MemoryProxy(config.data)
25090 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
25092 * Ext JS Library 1.1.1
25093 * Copyright(c) 2006-2007, Ext JS, LLC.
25095 * Originally Released Under LGPL - original licence link has changed is not relivant.
25098 * <script type="text/javascript">
25103 * @extends Roo.data.Store
25104 * @class Roo.data.JsonStore
25105 * Small helper class to make creating Stores for JSON data easier. <br/>
25107 var store = new Roo.data.JsonStore({
25108 url: 'get-images.php',
25110 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
25113 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
25114 * JsonReader and HttpProxy (unless inline data is provided).</b>
25115 * @cfg {Array} fields An array of field definition objects, or field name strings.
25117 * @param {Object} config
25119 Roo.data.JsonStore = function(c){
25120 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
25121 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
25122 reader: new Roo.data.JsonReader(c, c.fields)
25125 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
25127 * Ext JS Library 1.1.1
25128 * Copyright(c) 2006-2007, Ext JS, LLC.
25130 * Originally Released Under LGPL - original licence link has changed is not relivant.
25133 * <script type="text/javascript">
25137 Roo.data.Field = function(config){
25138 if(typeof config == "string"){
25139 config = {name: config};
25141 Roo.apply(this, config);
25144 this.type = "auto";
25147 var st = Roo.data.SortTypes;
25148 // named sortTypes are supported, here we look them up
25149 if(typeof this.sortType == "string"){
25150 this.sortType = st[this.sortType];
25153 // set default sortType for strings and dates
25154 if(!this.sortType){
25157 this.sortType = st.asUCString;
25160 this.sortType = st.asDate;
25163 this.sortType = st.none;
25168 var stripRe = /[\$,%]/g;
25170 // prebuilt conversion function for this field, instead of
25171 // switching every time we're reading a value
25173 var cv, dateFormat = this.dateFormat;
25178 cv = function(v){ return v; };
25181 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
25185 return v !== undefined && v !== null && v !== '' ?
25186 parseInt(String(v).replace(stripRe, ""), 10) : '';
25191 return v !== undefined && v !== null && v !== '' ?
25192 parseFloat(String(v).replace(stripRe, ""), 10) : '';
25197 cv = function(v){ return v === true || v === "true" || v == 1; };
25204 if(v instanceof Date){
25208 if(dateFormat == "timestamp"){
25209 return new Date(v*1000);
25211 return Date.parseDate(v, dateFormat);
25213 var parsed = Date.parse(v);
25214 return parsed ? new Date(parsed) : null;
25223 Roo.data.Field.prototype = {
25231 * Ext JS Library 1.1.1
25232 * Copyright(c) 2006-2007, Ext JS, LLC.
25234 * Originally Released Under LGPL - original licence link has changed is not relivant.
25237 * <script type="text/javascript">
25240 // Base class for reading structured data from a data source. This class is intended to be
25241 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
25244 * @class Roo.data.DataReader
25246 * Base class for reading structured data from a data source. This class is intended to be
25247 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
25250 Roo.data.DataReader = function(meta, recordType){
25254 this.recordType = recordType instanceof Array ?
25255 Roo.data.Record.create(recordType) : recordType;
25258 Roo.data.DataReader.prototype = {
25261 readerType : 'Data',
25263 * Create an empty record
25264 * @param {Object} data (optional) - overlay some values
25265 * @return {Roo.data.Record} record created.
25267 newRow : function(d) {
25269 this.recordType.prototype.fields.each(function(c) {
25271 case 'int' : da[c.name] = 0; break;
25272 case 'date' : da[c.name] = new Date(); break;
25273 case 'float' : da[c.name] = 0.0; break;
25274 case 'boolean' : da[c.name] = false; break;
25275 default : da[c.name] = ""; break;
25279 return new this.recordType(Roo.apply(da, d));
25285 * Ext JS Library 1.1.1
25286 * Copyright(c) 2006-2007, Ext JS, LLC.
25288 * Originally Released Under LGPL - original licence link has changed is not relivant.
25291 * <script type="text/javascript">
25295 * @class Roo.data.DataProxy
25296 * @extends Roo.util.Observable
25298 * This class is an abstract base class for implementations which provide retrieval of
25299 * unformatted data objects.<br>
25301 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
25302 * (of the appropriate type which knows how to parse the data object) to provide a block of
25303 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
25305 * Custom implementations must implement the load method as described in
25306 * {@link Roo.data.HttpProxy#load}.
25308 Roo.data.DataProxy = function(){
25311 * @event beforeload
25312 * Fires before a network request is made to retrieve a data object.
25313 * @param {Object} This DataProxy object.
25314 * @param {Object} params The params parameter to the load function.
25319 * Fires before the load method's callback is called.
25320 * @param {Object} This DataProxy object.
25321 * @param {Object} o The data object.
25322 * @param {Object} arg The callback argument object passed to the load function.
25326 * @event loadexception
25327 * Fires if an Exception occurs during data retrieval.
25328 * @param {Object} This DataProxy object.
25329 * @param {Object} o The data object.
25330 * @param {Object} arg The callback argument object passed to the load function.
25331 * @param {Object} e The Exception.
25333 loadexception : true
25335 Roo.data.DataProxy.superclass.constructor.call(this);
25338 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
25341 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
25345 * Ext JS Library 1.1.1
25346 * Copyright(c) 2006-2007, Ext JS, LLC.
25348 * Originally Released Under LGPL - original licence link has changed is not relivant.
25351 * <script type="text/javascript">
25354 * @class Roo.data.MemoryProxy
25355 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
25356 * to the Reader when its load method is called.
25358 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
25360 Roo.data.MemoryProxy = function(data){
25364 Roo.data.MemoryProxy.superclass.constructor.call(this);
25368 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
25371 * Load data from the requested source (in this case an in-memory
25372 * data object passed to the constructor), read the data object into
25373 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
25374 * process that block using the passed callback.
25375 * @param {Object} params This parameter is not used by the MemoryProxy class.
25376 * @param {Roo.data.DataReader} reader The Reader object which converts the data
25377 * object into a block of Roo.data.Records.
25378 * @param {Function} callback The function into which to pass the block of Roo.data.records.
25379 * The function must be passed <ul>
25380 * <li>The Record block object</li>
25381 * <li>The "arg" argument from the load function</li>
25382 * <li>A boolean success indicator</li>
25384 * @param {Object} scope The scope in which to call the callback
25385 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
25387 load : function(params, reader, callback, scope, arg){
25388 params = params || {};
25391 result = reader.readRecords(params.data ? params.data :this.data);
25393 this.fireEvent("loadexception", this, arg, null, e);
25394 callback.call(scope, null, arg, false);
25397 callback.call(scope, result, arg, true);
25401 update : function(params, records){
25406 * Ext JS Library 1.1.1
25407 * Copyright(c) 2006-2007, Ext JS, LLC.
25409 * Originally Released Under LGPL - original licence link has changed is not relivant.
25412 * <script type="text/javascript">
25415 * @class Roo.data.HttpProxy
25416 * @extends Roo.data.DataProxy
25417 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
25418 * configured to reference a certain URL.<br><br>
25420 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
25421 * from which the running page was served.<br><br>
25423 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
25425 * Be aware that to enable the browser to parse an XML document, the server must set
25426 * the Content-Type header in the HTTP response to "text/xml".
25428 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
25429 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
25430 * will be used to make the request.
25432 Roo.data.HttpProxy = function(conn){
25433 Roo.data.HttpProxy.superclass.constructor.call(this);
25434 // is conn a conn config or a real conn?
25436 this.useAjax = !conn || !conn.events;
25440 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
25441 // thse are take from connection...
25444 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
25447 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
25448 * extra parameters to each request made by this object. (defaults to undefined)
25451 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
25452 * to each request made by this object. (defaults to undefined)
25455 * @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)
25458 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
25461 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
25467 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
25471 * Return the {@link Roo.data.Connection} object being used by this Proxy.
25472 * @return {Connection} The Connection object. This object may be used to subscribe to events on
25473 * a finer-grained basis than the DataProxy events.
25475 getConnection : function(){
25476 return this.useAjax ? Roo.Ajax : this.conn;
25480 * Load data from the configured {@link Roo.data.Connection}, read the data object into
25481 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
25482 * process that block using the passed callback.
25483 * @param {Object} params An object containing properties which are to be used as HTTP parameters
25484 * for the request to the remote server.
25485 * @param {Roo.data.DataReader} reader The Reader object which converts the data
25486 * object into a block of Roo.data.Records.
25487 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
25488 * The function must be passed <ul>
25489 * <li>The Record block object</li>
25490 * <li>The "arg" argument from the load function</li>
25491 * <li>A boolean success indicator</li>
25493 * @param {Object} scope The scope in which to call the callback
25494 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
25496 load : function(params, reader, callback, scope, arg){
25497 if(this.fireEvent("beforeload", this, params) !== false){
25499 params : params || {},
25501 callback : callback,
25506 callback : this.loadResponse,
25510 Roo.applyIf(o, this.conn);
25511 if(this.activeRequest){
25512 Roo.Ajax.abort(this.activeRequest);
25514 this.activeRequest = Roo.Ajax.request(o);
25516 this.conn.request(o);
25519 callback.call(scope||this, null, arg, false);
25524 loadResponse : function(o, success, response){
25525 delete this.activeRequest;
25527 this.fireEvent("loadexception", this, o, response);
25528 o.request.callback.call(o.request.scope, null, o.request.arg, false);
25533 result = o.reader.read(response);
25536 o.raw = { errorMsg : response.responseText };
25537 this.fireEvent("loadexception", this, o, response, e);
25538 o.request.callback.call(o.request.scope, o, o.request.arg, false);
25542 this.fireEvent("load", this, o, o.request.arg);
25543 o.request.callback.call(o.request.scope, result, o.request.arg, true);
25547 update : function(dataSet){
25552 updateResponse : function(dataSet){
25557 * Ext JS Library 1.1.1
25558 * Copyright(c) 2006-2007, Ext JS, LLC.
25560 * Originally Released Under LGPL - original licence link has changed is not relivant.
25563 * <script type="text/javascript">
25567 * @class Roo.data.ScriptTagProxy
25568 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
25569 * other than the originating domain of the running page.<br><br>
25571 * <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
25572 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
25574 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
25575 * source code that is used as the source inside a <script> tag.<br><br>
25577 * In order for the browser to process the returned data, the server must wrap the data object
25578 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
25579 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
25580 * depending on whether the callback name was passed:
25583 boolean scriptTag = false;
25584 String cb = request.getParameter("callback");
25587 response.setContentType("text/javascript");
25589 response.setContentType("application/x-json");
25591 Writer out = response.getWriter();
25593 out.write(cb + "(");
25595 out.print(dataBlock.toJsonString());
25602 * @param {Object} config A configuration object.
25604 Roo.data.ScriptTagProxy = function(config){
25605 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
25606 Roo.apply(this, config);
25607 this.head = document.getElementsByTagName("head")[0];
25610 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
25612 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
25614 * @cfg {String} url The URL from which to request the data object.
25617 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
25621 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
25622 * the server the name of the callback function set up by the load call to process the returned data object.
25623 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
25624 * javascript output which calls this named function passing the data object as its only parameter.
25626 callbackParam : "callback",
25628 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
25629 * name to the request.
25634 * Load data from the configured URL, read the data object into
25635 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
25636 * process that block using the passed callback.
25637 * @param {Object} params An object containing properties which are to be used as HTTP parameters
25638 * for the request to the remote server.
25639 * @param {Roo.data.DataReader} reader The Reader object which converts the data
25640 * object into a block of Roo.data.Records.
25641 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
25642 * The function must be passed <ul>
25643 * <li>The Record block object</li>
25644 * <li>The "arg" argument from the load function</li>
25645 * <li>A boolean success indicator</li>
25647 * @param {Object} scope The scope in which to call the callback
25648 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
25650 load : function(params, reader, callback, scope, arg){
25651 if(this.fireEvent("beforeload", this, params) !== false){
25653 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
25655 var url = this.url;
25656 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
25658 url += "&_dc=" + (new Date().getTime());
25660 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
25663 cb : "stcCallback"+transId,
25664 scriptId : "stcScript"+transId,
25668 callback : callback,
25674 window[trans.cb] = function(o){
25675 conn.handleResponse(o, trans);
25678 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
25680 if(this.autoAbort !== false){
25684 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
25686 var script = document.createElement("script");
25687 script.setAttribute("src", url);
25688 script.setAttribute("type", "text/javascript");
25689 script.setAttribute("id", trans.scriptId);
25690 this.head.appendChild(script);
25692 this.trans = trans;
25694 callback.call(scope||this, null, arg, false);
25699 isLoading : function(){
25700 return this.trans ? true : false;
25704 * Abort the current server request.
25706 abort : function(){
25707 if(this.isLoading()){
25708 this.destroyTrans(this.trans);
25713 destroyTrans : function(trans, isLoaded){
25714 this.head.removeChild(document.getElementById(trans.scriptId));
25715 clearTimeout(trans.timeoutId);
25717 window[trans.cb] = undefined;
25719 delete window[trans.cb];
25722 // if hasn't been loaded, wait for load to remove it to prevent script error
25723 window[trans.cb] = function(){
25724 window[trans.cb] = undefined;
25726 delete window[trans.cb];
25733 handleResponse : function(o, trans){
25734 this.trans = false;
25735 this.destroyTrans(trans, true);
25738 result = trans.reader.readRecords(o);
25740 this.fireEvent("loadexception", this, o, trans.arg, e);
25741 trans.callback.call(trans.scope||window, null, trans.arg, false);
25744 this.fireEvent("load", this, o, trans.arg);
25745 trans.callback.call(trans.scope||window, result, trans.arg, true);
25749 handleFailure : function(trans){
25750 this.trans = false;
25751 this.destroyTrans(trans, false);
25752 this.fireEvent("loadexception", this, null, trans.arg);
25753 trans.callback.call(trans.scope||window, null, trans.arg, false);
25757 * Ext JS Library 1.1.1
25758 * Copyright(c) 2006-2007, Ext JS, LLC.
25760 * Originally Released Under LGPL - original licence link has changed is not relivant.
25763 * <script type="text/javascript">
25767 * @class Roo.data.JsonReader
25768 * @extends Roo.data.DataReader
25769 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
25770 * based on mappings in a provided Roo.data.Record constructor.
25772 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
25773 * in the reply previously.
25778 var RecordDef = Roo.data.Record.create([
25779 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
25780 {name: 'occupation'} // This field will use "occupation" as the mapping.
25782 var myReader = new Roo.data.JsonReader({
25783 totalProperty: "results", // The property which contains the total dataset size (optional)
25784 root: "rows", // The property which contains an Array of row objects
25785 id: "id" // The property within each row object that provides an ID for the record (optional)
25789 * This would consume a JSON file like this:
25791 { 'results': 2, 'rows': [
25792 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
25793 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
25796 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
25797 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
25798 * paged from the remote server.
25799 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
25800 * @cfg {String} root name of the property which contains the Array of row objects.
25801 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
25802 * @cfg {Array} fields Array of field definition objects
25804 * Create a new JsonReader
25805 * @param {Object} meta Metadata configuration options
25806 * @param {Object} recordType Either an Array of field definition objects,
25807 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
25809 Roo.data.JsonReader = function(meta, recordType){
25812 // set some defaults:
25813 Roo.applyIf(meta, {
25814 totalProperty: 'total',
25815 successProperty : 'success',
25820 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
25822 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
25824 readerType : 'Json',
25827 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
25828 * Used by Store query builder to append _requestMeta to params.
25831 metaFromRemote : false,
25833 * This method is only used by a DataProxy which has retrieved data from a remote server.
25834 * @param {Object} response The XHR object which contains the JSON data in its responseText.
25835 * @return {Object} data A data block which is used by an Roo.data.Store object as
25836 * a cache of Roo.data.Records.
25838 read : function(response){
25839 var json = response.responseText;
25841 var o = /* eval:var:o */ eval("("+json+")");
25843 throw {message: "JsonReader.read: Json object not found"};
25849 this.metaFromRemote = true;
25850 this.meta = o.metaData;
25851 this.recordType = Roo.data.Record.create(o.metaData.fields);
25852 this.onMetaChange(this.meta, this.recordType, o);
25854 return this.readRecords(o);
25857 // private function a store will implement
25858 onMetaChange : function(meta, recordType, o){
25865 simpleAccess: function(obj, subsc) {
25872 getJsonAccessor: function(){
25874 return function(expr) {
25876 return(re.test(expr))
25877 ? new Function("obj", "return obj." + expr)
25882 return Roo.emptyFn;
25887 * Create a data block containing Roo.data.Records from an XML document.
25888 * @param {Object} o An object which contains an Array of row objects in the property specified
25889 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
25890 * which contains the total size of the dataset.
25891 * @return {Object} data A data block which is used by an Roo.data.Store object as
25892 * a cache of Roo.data.Records.
25894 readRecords : function(o){
25896 * After any data loads, the raw JSON data is available for further custom processing.
25900 var s = this.meta, Record = this.recordType,
25901 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
25903 // Generate extraction functions for the totalProperty, the root, the id, and for each field
25905 if(s.totalProperty) {
25906 this.getTotal = this.getJsonAccessor(s.totalProperty);
25908 if(s.successProperty) {
25909 this.getSuccess = this.getJsonAccessor(s.successProperty);
25911 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
25913 var g = this.getJsonAccessor(s.id);
25914 this.getId = function(rec) {
25916 return (r === undefined || r === "") ? null : r;
25919 this.getId = function(){return null;};
25922 for(var jj = 0; jj < fl; jj++){
25924 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
25925 this.ef[jj] = this.getJsonAccessor(map);
25929 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
25930 if(s.totalProperty){
25931 var vt = parseInt(this.getTotal(o), 10);
25936 if(s.successProperty){
25937 var vs = this.getSuccess(o);
25938 if(vs === false || vs === 'false'){
25943 for(var i = 0; i < c; i++){
25946 var id = this.getId(n);
25947 for(var j = 0; j < fl; j++){
25949 var v = this.ef[j](n);
25951 Roo.log('missing convert for ' + f.name);
25955 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
25959 raw : { errorMsg : "JSON Reader Error: fields or metadata not available to create Record" },
25965 var record = new Record(values, id);
25967 records[i] = record;
25973 totalRecords : totalRecords
25976 // used when loading children.. @see loadDataFromChildren
25977 toLoadData: function(rec)
25979 // expect rec just to be an array.. eg [a,b,c, [...] << cn ]
25980 var data = typeof(rec.data.cn) == 'undefined' ? [] : rec.data.cn;
25981 return { data : data, total : data.length };
25986 * Ext JS Library 1.1.1
25987 * Copyright(c) 2006-2007, Ext JS, LLC.
25989 * Originally Released Under LGPL - original licence link has changed is not relivant.
25992 * <script type="text/javascript">
25996 * @class Roo.data.XmlReader
25997 * @extends Roo.data.DataReader
25998 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
25999 * based on mappings in a provided Roo.data.Record constructor.<br><br>
26001 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
26002 * header in the HTTP response must be set to "text/xml".</em>
26006 var RecordDef = Roo.data.Record.create([
26007 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
26008 {name: 'occupation'} // This field will use "occupation" as the mapping.
26010 var myReader = new Roo.data.XmlReader({
26011 totalRecords: "results", // The element which contains the total dataset size (optional)
26012 record: "row", // The repeated element which contains row information
26013 id: "id" // The element within the row that provides an ID for the record (optional)
26017 * This would consume an XML file like this:
26021 <results>2</results>
26024 <name>Bill</name>
26025 <occupation>Gardener</occupation>
26029 <name>Ben</name>
26030 <occupation>Horticulturalist</occupation>
26034 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
26035 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
26036 * paged from the remote server.
26037 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
26038 * @cfg {String} success The DomQuery path to the success attribute used by forms.
26039 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
26040 * a record identifier value.
26042 * Create a new XmlReader
26043 * @param {Object} meta Metadata configuration options
26044 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
26045 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
26046 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
26048 Roo.data.XmlReader = function(meta, recordType){
26050 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
26052 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
26054 readerType : 'Xml',
26057 * This method is only used by a DataProxy which has retrieved data from a remote server.
26058 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
26059 * to contain a method called 'responseXML' that returns an XML document object.
26060 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
26061 * a cache of Roo.data.Records.
26063 read : function(response){
26064 var doc = response.responseXML;
26066 throw {message: "XmlReader.read: XML Document not available"};
26068 return this.readRecords(doc);
26072 * Create a data block containing Roo.data.Records from an XML document.
26073 * @param {Object} doc A parsed XML document.
26074 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
26075 * a cache of Roo.data.Records.
26077 readRecords : function(doc){
26079 * After any data loads/reads, the raw XML Document is available for further custom processing.
26080 * @type XMLDocument
26082 this.xmlData = doc;
26083 var root = doc.documentElement || doc;
26084 var q = Roo.DomQuery;
26085 var recordType = this.recordType, fields = recordType.prototype.fields;
26086 var sid = this.meta.id;
26087 var totalRecords = 0, success = true;
26088 if(this.meta.totalRecords){
26089 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
26092 if(this.meta.success){
26093 var sv = q.selectValue(this.meta.success, root, true);
26094 success = sv !== false && sv !== 'false';
26097 var ns = q.select(this.meta.record, root);
26098 for(var i = 0, len = ns.length; i < len; i++) {
26101 var id = sid ? q.selectValue(sid, n) : undefined;
26102 for(var j = 0, jlen = fields.length; j < jlen; j++){
26103 var f = fields.items[j];
26104 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
26106 values[f.name] = v;
26108 var record = new recordType(values, id);
26110 records[records.length] = record;
26116 totalRecords : totalRecords || records.length
26121 * Ext JS Library 1.1.1
26122 * Copyright(c) 2006-2007, Ext JS, LLC.
26124 * Originally Released Under LGPL - original licence link has changed is not relivant.
26127 * <script type="text/javascript">
26131 * @class Roo.data.ArrayReader
26132 * @extends Roo.data.DataReader
26133 * Data reader class to create an Array of Roo.data.Record objects from an Array.
26134 * Each element of that Array represents a row of data fields. The
26135 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
26136 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
26140 var RecordDef = Roo.data.Record.create([
26141 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
26142 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
26144 var myReader = new Roo.data.ArrayReader({
26145 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
26149 * This would consume an Array like this:
26151 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
26155 * Create a new JsonReader
26156 * @param {Object} meta Metadata configuration options.
26157 * @param {Object|Array} recordType Either an Array of field definition objects
26159 * @cfg {Array} fields Array of field definition objects
26160 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
26161 * as specified to {@link Roo.data.Record#create},
26162 * or an {@link Roo.data.Record} object
26165 * created using {@link Roo.data.Record#create}.
26167 Roo.data.ArrayReader = function(meta, recordType)
26169 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType||meta.fields);
26172 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
26175 * Create a data block containing Roo.data.Records from an XML document.
26176 * @param {Object} o An Array of row objects which represents the dataset.
26177 * @return {Object} A data block which is used by an {@link Roo.data.Store} object as
26178 * a cache of Roo.data.Records.
26180 readRecords : function(o)
26182 var sid = this.meta ? this.meta.id : null;
26183 var recordType = this.recordType, fields = recordType.prototype.fields;
26186 for(var i = 0; i < root.length; i++){
26189 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
26190 for(var j = 0, jlen = fields.length; j < jlen; j++){
26191 var f = fields.items[j];
26192 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
26193 var v = n[k] !== undefined ? n[k] : f.defaultValue;
26195 values[f.name] = v;
26197 var record = new recordType(values, id);
26199 records[records.length] = record;
26203 totalRecords : records.length
26206 // used when loading children.. @see loadDataFromChildren
26207 toLoadData: function(rec)
26209 // expect rec just to be an array.. eg [a,b,c, [...] << cn ]
26210 return typeof(rec.data.cn) == 'undefined' ? [] : rec.data.cn;
26217 * Ext JS Library 1.1.1
26218 * Copyright(c) 2006-2007, Ext JS, LLC.
26220 * Originally Released Under LGPL - original licence link has changed is not relivant.
26223 * <script type="text/javascript">
26228 * @class Roo.data.Tree
26229 * @extends Roo.util.Observable
26230 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
26231 * in the tree have most standard DOM functionality.
26233 * @param {Node} root (optional) The root node
26235 Roo.data.Tree = function(root){
26236 this.nodeHash = {};
26238 * The root node for this tree
26243 this.setRootNode(root);
26248 * Fires when a new child node is appended to a node in this tree.
26249 * @param {Tree} tree The owner tree
26250 * @param {Node} parent The parent node
26251 * @param {Node} node The newly appended node
26252 * @param {Number} index The index of the newly appended node
26257 * Fires when a child node is removed from a node in this tree.
26258 * @param {Tree} tree The owner tree
26259 * @param {Node} parent The parent node
26260 * @param {Node} node The child node removed
26265 * Fires when a node is moved to a new location in the tree
26266 * @param {Tree} tree The owner tree
26267 * @param {Node} node The node moved
26268 * @param {Node} oldParent The old parent of this node
26269 * @param {Node} newParent The new parent of this node
26270 * @param {Number} index The index it was moved to
26275 * Fires when a new child node is inserted in a node in this tree.
26276 * @param {Tree} tree The owner tree
26277 * @param {Node} parent The parent node
26278 * @param {Node} node The child node inserted
26279 * @param {Node} refNode The child node the node was inserted before
26283 * @event beforeappend
26284 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
26285 * @param {Tree} tree The owner tree
26286 * @param {Node} parent The parent node
26287 * @param {Node} node The child node to be appended
26289 "beforeappend" : true,
26291 * @event beforeremove
26292 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
26293 * @param {Tree} tree The owner tree
26294 * @param {Node} parent The parent node
26295 * @param {Node} node The child node to be removed
26297 "beforeremove" : true,
26299 * @event beforemove
26300 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
26301 * @param {Tree} tree The owner tree
26302 * @param {Node} node The node being moved
26303 * @param {Node} oldParent The parent of the node
26304 * @param {Node} newParent The new parent the node is moving to
26305 * @param {Number} index The index it is being moved to
26307 "beforemove" : true,
26309 * @event beforeinsert
26310 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
26311 * @param {Tree} tree The owner tree
26312 * @param {Node} parent The parent node
26313 * @param {Node} node The child node to be inserted
26314 * @param {Node} refNode The child node the node is being inserted before
26316 "beforeinsert" : true
26319 Roo.data.Tree.superclass.constructor.call(this);
26322 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
26323 pathSeparator: "/",
26325 proxyNodeEvent : function(){
26326 return this.fireEvent.apply(this, arguments);
26330 * Returns the root node for this tree.
26333 getRootNode : function(){
26338 * Sets the root node for this tree.
26339 * @param {Node} node
26342 setRootNode : function(node){
26344 node.ownerTree = this;
26345 node.isRoot = true;
26346 this.registerNode(node);
26351 * Gets a node in this tree by its id.
26352 * @param {String} id
26355 getNodeById : function(id){
26356 return this.nodeHash[id];
26359 registerNode : function(node){
26360 this.nodeHash[node.id] = node;
26363 unregisterNode : function(node){
26364 delete this.nodeHash[node.id];
26367 toString : function(){
26368 return "[Tree"+(this.id?" "+this.id:"")+"]";
26373 * @class Roo.data.Node
26374 * @extends Roo.util.Observable
26375 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
26376 * @cfg {String} id The id for this node. If one is not specified, one is generated.
26378 * @param {Object} attributes The attributes/config for the node
26380 Roo.data.Node = function(attributes){
26382 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
26385 this.attributes = attributes || {};
26386 this.leaf = this.attributes.leaf;
26388 * The node id. @type String
26390 this.id = this.attributes.id;
26392 this.id = Roo.id(null, "ynode-");
26393 this.attributes.id = this.id;
26398 * All child nodes of this node. @type Array
26400 this.childNodes = [];
26401 if(!this.childNodes.indexOf){ // indexOf is a must
26402 this.childNodes.indexOf = function(o){
26403 for(var i = 0, len = this.length; i < len; i++){
26412 * The parent node for this node. @type Node
26414 this.parentNode = null;
26416 * The first direct child node of this node, or null if this node has no child nodes. @type Node
26418 this.firstChild = null;
26420 * The last direct child node of this node, or null if this node has no child nodes. @type Node
26422 this.lastChild = null;
26424 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
26426 this.previousSibling = null;
26428 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
26430 this.nextSibling = null;
26435 * Fires when a new child node is appended
26436 * @param {Tree} tree The owner tree
26437 * @param {Node} this This node
26438 * @param {Node} node The newly appended node
26439 * @param {Number} index The index of the newly appended node
26444 * Fires when a child node is removed
26445 * @param {Tree} tree The owner tree
26446 * @param {Node} this This node
26447 * @param {Node} node The removed node
26452 * Fires when this node is moved to a new location in the tree
26453 * @param {Tree} tree The owner tree
26454 * @param {Node} this This node
26455 * @param {Node} oldParent The old parent of this node
26456 * @param {Node} newParent The new parent of this node
26457 * @param {Number} index The index it was moved to
26462 * Fires when a new child node is inserted.
26463 * @param {Tree} tree The owner tree
26464 * @param {Node} this This node
26465 * @param {Node} node The child node inserted
26466 * @param {Node} refNode The child node the node was inserted before
26470 * @event beforeappend
26471 * Fires before a new child is appended, return false to cancel the append.
26472 * @param {Tree} tree The owner tree
26473 * @param {Node} this This node
26474 * @param {Node} node The child node to be appended
26476 "beforeappend" : true,
26478 * @event beforeremove
26479 * Fires before a child is removed, return false to cancel the remove.
26480 * @param {Tree} tree The owner tree
26481 * @param {Node} this This node
26482 * @param {Node} node The child node to be removed
26484 "beforeremove" : true,
26486 * @event beforemove
26487 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
26488 * @param {Tree} tree The owner tree
26489 * @param {Node} this This node
26490 * @param {Node} oldParent The parent of this node
26491 * @param {Node} newParent The new parent this node is moving to
26492 * @param {Number} index The index it is being moved to
26494 "beforemove" : true,
26496 * @event beforeinsert
26497 * Fires before a new child is inserted, return false to cancel the insert.
26498 * @param {Tree} tree The owner tree
26499 * @param {Node} this This node
26500 * @param {Node} node The child node to be inserted
26501 * @param {Node} refNode The child node the node is being inserted before
26503 "beforeinsert" : true
26505 this.listeners = this.attributes.listeners;
26506 Roo.data.Node.superclass.constructor.call(this);
26509 Roo.extend(Roo.data.Node, Roo.util.Observable, {
26510 fireEvent : function(evtName){
26511 // first do standard event for this node
26512 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
26515 // then bubble it up to the tree if the event wasn't cancelled
26516 var ot = this.getOwnerTree();
26518 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
26526 * Returns true if this node is a leaf
26527 * @return {Boolean}
26529 isLeaf : function(){
26530 return this.leaf === true;
26534 setFirstChild : function(node){
26535 this.firstChild = node;
26539 setLastChild : function(node){
26540 this.lastChild = node;
26545 * Returns true if this node is the last child of its parent
26546 * @return {Boolean}
26548 isLast : function(){
26549 return (!this.parentNode ? true : this.parentNode.lastChild == this);
26553 * Returns true if this node is the first child of its parent
26554 * @return {Boolean}
26556 isFirst : function(){
26557 return (!this.parentNode ? true : this.parentNode.firstChild == this);
26560 hasChildNodes : function(){
26561 return !this.isLeaf() && this.childNodes.length > 0;
26565 * Insert node(s) as the last child node of this node.
26566 * @param {Node/Array} node The node or Array of nodes to append
26567 * @return {Node} The appended node if single append, or null if an array was passed
26569 appendChild : function(node){
26571 if(node instanceof Array){
26573 }else if(arguments.length > 1){
26577 // if passed an array or multiple args do them one by one
26579 for(var i = 0, len = multi.length; i < len; i++) {
26580 this.appendChild(multi[i]);
26583 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
26586 var index = this.childNodes.length;
26587 var oldParent = node.parentNode;
26588 // it's a move, make sure we move it cleanly
26590 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
26593 oldParent.removeChild(node);
26596 index = this.childNodes.length;
26598 this.setFirstChild(node);
26600 this.childNodes.push(node);
26601 node.parentNode = this;
26602 var ps = this.childNodes[index-1];
26604 node.previousSibling = ps;
26605 ps.nextSibling = node;
26607 node.previousSibling = null;
26609 node.nextSibling = null;
26610 this.setLastChild(node);
26611 node.setOwnerTree(this.getOwnerTree());
26612 this.fireEvent("append", this.ownerTree, this, node, index);
26613 if(this.ownerTree) {
26614 this.ownerTree.fireEvent("appendnode", this, node, index);
26617 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
26624 * Removes a child node from this node.
26625 * @param {Node} node The node to remove
26626 * @return {Node} The removed node
26628 removeChild : function(node){
26629 var index = this.childNodes.indexOf(node);
26633 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
26637 // remove it from childNodes collection
26638 this.childNodes.splice(index, 1);
26641 if(node.previousSibling){
26642 node.previousSibling.nextSibling = node.nextSibling;
26644 if(node.nextSibling){
26645 node.nextSibling.previousSibling = node.previousSibling;
26648 // update child refs
26649 if(this.firstChild == node){
26650 this.setFirstChild(node.nextSibling);
26652 if(this.lastChild == node){
26653 this.setLastChild(node.previousSibling);
26656 node.setOwnerTree(null);
26657 // clear any references from the node
26658 node.parentNode = null;
26659 node.previousSibling = null;
26660 node.nextSibling = null;
26661 this.fireEvent("remove", this.ownerTree, this, node);
26666 * Inserts the first node before the second node in this nodes childNodes collection.
26667 * @param {Node} node The node to insert
26668 * @param {Node} refNode The node to insert before (if null the node is appended)
26669 * @return {Node} The inserted node
26671 insertBefore : function(node, refNode){
26672 if(!refNode){ // like standard Dom, refNode can be null for append
26673 return this.appendChild(node);
26676 if(node == refNode){
26680 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
26683 var index = this.childNodes.indexOf(refNode);
26684 var oldParent = node.parentNode;
26685 var refIndex = index;
26687 // when moving internally, indexes will change after remove
26688 if(oldParent == this && this.childNodes.indexOf(node) < index){
26692 // it's a move, make sure we move it cleanly
26694 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
26697 oldParent.removeChild(node);
26700 this.setFirstChild(node);
26702 this.childNodes.splice(refIndex, 0, node);
26703 node.parentNode = this;
26704 var ps = this.childNodes[refIndex-1];
26706 node.previousSibling = ps;
26707 ps.nextSibling = node;
26709 node.previousSibling = null;
26711 node.nextSibling = refNode;
26712 refNode.previousSibling = node;
26713 node.setOwnerTree(this.getOwnerTree());
26714 this.fireEvent("insert", this.ownerTree, this, node, refNode);
26716 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
26722 * Returns the child node at the specified index.
26723 * @param {Number} index
26726 item : function(index){
26727 return this.childNodes[index];
26731 * Replaces one child node in this node with another.
26732 * @param {Node} newChild The replacement node
26733 * @param {Node} oldChild The node to replace
26734 * @return {Node} The replaced node
26736 replaceChild : function(newChild, oldChild){
26737 this.insertBefore(newChild, oldChild);
26738 this.removeChild(oldChild);
26743 * Returns the index of a child node
26744 * @param {Node} node
26745 * @return {Number} The index of the node or -1 if it was not found
26747 indexOf : function(child){
26748 return this.childNodes.indexOf(child);
26752 * Returns the tree this node is in.
26755 getOwnerTree : function(){
26756 // if it doesn't have one, look for one
26757 if(!this.ownerTree){
26761 this.ownerTree = p.ownerTree;
26767 return this.ownerTree;
26771 * Returns depth of this node (the root node has a depth of 0)
26774 getDepth : function(){
26777 while(p.parentNode){
26785 setOwnerTree : function(tree){
26786 // if it's move, we need to update everyone
26787 if(tree != this.ownerTree){
26788 if(this.ownerTree){
26789 this.ownerTree.unregisterNode(this);
26791 this.ownerTree = tree;
26792 var cs = this.childNodes;
26793 for(var i = 0, len = cs.length; i < len; i++) {
26794 cs[i].setOwnerTree(tree);
26797 tree.registerNode(this);
26803 * Returns the path for this node. The path can be used to expand or select this node programmatically.
26804 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
26805 * @return {String} The path
26807 getPath : function(attr){
26808 attr = attr || "id";
26809 var p = this.parentNode;
26810 var b = [this.attributes[attr]];
26812 b.unshift(p.attributes[attr]);
26815 var sep = this.getOwnerTree().pathSeparator;
26816 return sep + b.join(sep);
26820 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
26821 * function call will be the scope provided or the current node. The arguments to the function
26822 * will be the args provided or the current node. If the function returns false at any point,
26823 * the bubble is stopped.
26824 * @param {Function} fn The function to call
26825 * @param {Object} scope (optional) The scope of the function (defaults to current node)
26826 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
26828 bubble : function(fn, scope, args){
26831 if(fn.call(scope || p, args || p) === false){
26839 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
26840 * function call will be the scope provided or the current node. The arguments to the function
26841 * will be the args provided or the current node. If the function returns false at any point,
26842 * the cascade is stopped on that branch.
26843 * @param {Function} fn The function to call
26844 * @param {Object} scope (optional) The scope of the function (defaults to current node)
26845 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
26847 cascade : function(fn, scope, args){
26848 if(fn.call(scope || this, args || this) !== false){
26849 var cs = this.childNodes;
26850 for(var i = 0, len = cs.length; i < len; i++) {
26851 cs[i].cascade(fn, scope, args);
26857 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
26858 * function call will be the scope provided or the current node. The arguments to the function
26859 * will be the args provided or the current node. If the function returns false at any point,
26860 * the iteration stops.
26861 * @param {Function} fn The function to call
26862 * @param {Object} scope (optional) The scope of the function (defaults to current node)
26863 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
26865 eachChild : function(fn, scope, args){
26866 var cs = this.childNodes;
26867 for(var i = 0, len = cs.length; i < len; i++) {
26868 if(fn.call(scope || this, args || cs[i]) === false){
26875 * Finds the first child that has the attribute with the specified value.
26876 * @param {String} attribute The attribute name
26877 * @param {Mixed} value The value to search for
26878 * @return {Node} The found child or null if none was found
26880 findChild : function(attribute, value){
26881 var cs = this.childNodes;
26882 for(var i = 0, len = cs.length; i < len; i++) {
26883 if(cs[i].attributes[attribute] == value){
26891 * Finds the first child by a custom function. The child matches if the function passed
26893 * @param {Function} fn
26894 * @param {Object} scope (optional)
26895 * @return {Node} The found child or null if none was found
26897 findChildBy : function(fn, scope){
26898 var cs = this.childNodes;
26899 for(var i = 0, len = cs.length; i < len; i++) {
26900 if(fn.call(scope||cs[i], cs[i]) === true){
26908 * Sorts this nodes children using the supplied sort function
26909 * @param {Function} fn
26910 * @param {Object} scope (optional)
26912 sort : function(fn, scope){
26913 var cs = this.childNodes;
26914 var len = cs.length;
26916 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
26918 for(var i = 0; i < len; i++){
26920 n.previousSibling = cs[i-1];
26921 n.nextSibling = cs[i+1];
26923 this.setFirstChild(n);
26926 this.setLastChild(n);
26933 * Returns true if this node is an ancestor (at any point) of the passed node.
26934 * @param {Node} node
26935 * @return {Boolean}
26937 contains : function(node){
26938 return node.isAncestor(this);
26942 * Returns true if the passed node is an ancestor (at any point) of this node.
26943 * @param {Node} node
26944 * @return {Boolean}
26946 isAncestor : function(node){
26947 var p = this.parentNode;
26957 toString : function(){
26958 return "[Node"+(this.id?" "+this.id:"")+"]";
26962 * Ext JS Library 1.1.1
26963 * Copyright(c) 2006-2007, Ext JS, LLC.
26965 * Originally Released Under LGPL - original licence link has changed is not relivant.
26968 * <script type="text/javascript">
26973 * @class Roo.Shadow
26974 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
26975 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
26976 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
26978 * Create a new Shadow
26979 * @param {Object} config The config object
26981 Roo.Shadow = function(config){
26982 Roo.apply(this, config);
26983 if(typeof this.mode != "string"){
26984 this.mode = this.defaultMode;
26986 var o = this.offset, a = {h: 0};
26987 var rad = Math.floor(this.offset/2);
26988 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
26994 a.l -= this.offset + rad;
26995 a.t -= this.offset + rad;
27006 a.l -= (this.offset - rad);
27007 a.t -= this.offset + rad;
27009 a.w -= (this.offset - rad)*2;
27020 a.l -= (this.offset - rad);
27021 a.t -= (this.offset - rad);
27023 a.w -= (this.offset + rad + 1);
27024 a.h -= (this.offset + rad);
27033 Roo.Shadow.prototype = {
27035 * @cfg {String} mode
27036 * The shadow display mode. Supports the following options:<br />
27037 * sides: Shadow displays on both sides and bottom only<br />
27038 * frame: Shadow displays equally on all four sides<br />
27039 * drop: Traditional bottom-right drop shadow (default)
27043 * @cfg {String} offset
27044 * The number of pixels to offset the shadow from the element (defaults to 4)
27049 defaultMode: "drop",
27052 * Displays the shadow under the target element
27053 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
27055 show : function(target){
27056 target = Roo.get(target);
27058 this.el = Roo.Shadow.Pool.pull();
27059 if(this.el.dom.nextSibling != target.dom){
27060 this.el.insertBefore(target);
27063 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
27065 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
27068 target.getLeft(true),
27069 target.getTop(true),
27073 this.el.dom.style.display = "block";
27077 * Returns true if the shadow is visible, else false
27079 isVisible : function(){
27080 return this.el ? true : false;
27084 * Direct alignment when values are already available. Show must be called at least once before
27085 * calling this method to ensure it is initialized.
27086 * @param {Number} left The target element left position
27087 * @param {Number} top The target element top position
27088 * @param {Number} width The target element width
27089 * @param {Number} height The target element height
27091 realign : function(l, t, w, h){
27095 var a = this.adjusts, d = this.el.dom, s = d.style;
27097 s.left = (l+a.l)+"px";
27098 s.top = (t+a.t)+"px";
27099 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
27101 if(s.width != sws || s.height != shs){
27105 var cn = d.childNodes;
27106 var sww = Math.max(0, (sw-12))+"px";
27107 cn[0].childNodes[1].style.width = sww;
27108 cn[1].childNodes[1].style.width = sww;
27109 cn[2].childNodes[1].style.width = sww;
27110 cn[1].style.height = Math.max(0, (sh-12))+"px";
27116 * Hides this shadow
27120 this.el.dom.style.display = "none";
27121 Roo.Shadow.Pool.push(this.el);
27127 * Adjust the z-index of this shadow
27128 * @param {Number} zindex The new z-index
27130 setZIndex : function(z){
27133 this.el.setStyle("z-index", z);
27138 // Private utility class that manages the internal Shadow cache
27139 Roo.Shadow.Pool = function(){
27141 var markup = Roo.isIE ?
27142 '<div class="x-ie-shadow"></div>' :
27143 '<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>';
27146 var sh = p.shift();
27148 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
27149 sh.autoBoxAdjust = false;
27154 push : function(sh){
27160 * Ext JS Library 1.1.1
27161 * Copyright(c) 2006-2007, Ext JS, LLC.
27163 * Originally Released Under LGPL - original licence link has changed is not relivant.
27166 * <script type="text/javascript">
27171 * @class Roo.SplitBar
27172 * @extends Roo.util.Observable
27173 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
27177 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
27178 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
27179 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
27180 split.minSize = 100;
27181 split.maxSize = 600;
27182 split.animate = true;
27183 split.on('moved', splitterMoved);
27186 * Create a new SplitBar
27187 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
27188 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
27189 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
27190 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
27191 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
27192 position of the SplitBar).
27194 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
27197 this.el = Roo.get(dragElement, true);
27198 this.el.dom.unselectable = "on";
27200 this.resizingEl = Roo.get(resizingElement, true);
27204 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
27205 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
27208 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
27211 * The minimum size of the resizing element. (Defaults to 0)
27217 * The maximum size of the resizing element. (Defaults to 2000)
27220 this.maxSize = 2000;
27223 * Whether to animate the transition to the new size
27226 this.animate = false;
27229 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
27232 this.useShim = false;
27237 if(!existingProxy){
27239 this.proxy = Roo.SplitBar.createProxy(this.orientation);
27241 this.proxy = Roo.get(existingProxy).dom;
27244 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
27247 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
27250 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
27253 this.dragSpecs = {};
27256 * @private The adapter to use to positon and resize elements
27258 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
27259 this.adapter.init(this);
27261 if(this.orientation == Roo.SplitBar.HORIZONTAL){
27263 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
27264 this.el.addClass("x-splitbar-h");
27267 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
27268 this.el.addClass("x-splitbar-v");
27274 * Fires when the splitter is moved (alias for {@link #event-moved})
27275 * @param {Roo.SplitBar} this
27276 * @param {Number} newSize the new width or height
27281 * Fires when the splitter is moved
27282 * @param {Roo.SplitBar} this
27283 * @param {Number} newSize the new width or height
27287 * @event beforeresize
27288 * Fires before the splitter is dragged
27289 * @param {Roo.SplitBar} this
27291 "beforeresize" : true,
27293 "beforeapply" : true
27296 Roo.util.Observable.call(this);
27299 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
27300 onStartProxyDrag : function(x, y){
27301 this.fireEvent("beforeresize", this);
27303 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
27305 o.enableDisplayMode("block");
27306 // all splitbars share the same overlay
27307 Roo.SplitBar.prototype.overlay = o;
27309 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
27310 this.overlay.show();
27311 Roo.get(this.proxy).setDisplayed("block");
27312 var size = this.adapter.getElementSize(this);
27313 this.activeMinSize = this.getMinimumSize();;
27314 this.activeMaxSize = this.getMaximumSize();;
27315 var c1 = size - this.activeMinSize;
27316 var c2 = Math.max(this.activeMaxSize - size, 0);
27317 if(this.orientation == Roo.SplitBar.HORIZONTAL){
27318 this.dd.resetConstraints();
27319 this.dd.setXConstraint(
27320 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
27321 this.placement == Roo.SplitBar.LEFT ? c2 : c1
27323 this.dd.setYConstraint(0, 0);
27325 this.dd.resetConstraints();
27326 this.dd.setXConstraint(0, 0);
27327 this.dd.setYConstraint(
27328 this.placement == Roo.SplitBar.TOP ? c1 : c2,
27329 this.placement == Roo.SplitBar.TOP ? c2 : c1
27332 this.dragSpecs.startSize = size;
27333 this.dragSpecs.startPoint = [x, y];
27334 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
27338 * @private Called after the drag operation by the DDProxy
27340 onEndProxyDrag : function(e){
27341 Roo.get(this.proxy).setDisplayed(false);
27342 var endPoint = Roo.lib.Event.getXY(e);
27344 this.overlay.hide();
27347 if(this.orientation == Roo.SplitBar.HORIZONTAL){
27348 newSize = this.dragSpecs.startSize +
27349 (this.placement == Roo.SplitBar.LEFT ?
27350 endPoint[0] - this.dragSpecs.startPoint[0] :
27351 this.dragSpecs.startPoint[0] - endPoint[0]
27354 newSize = this.dragSpecs.startSize +
27355 (this.placement == Roo.SplitBar.TOP ?
27356 endPoint[1] - this.dragSpecs.startPoint[1] :
27357 this.dragSpecs.startPoint[1] - endPoint[1]
27360 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
27361 if(newSize != this.dragSpecs.startSize){
27362 if(this.fireEvent('beforeapply', this, newSize) !== false){
27363 this.adapter.setElementSize(this, newSize);
27364 this.fireEvent("moved", this, newSize);
27365 this.fireEvent("resize", this, newSize);
27371 * Get the adapter this SplitBar uses
27372 * @return The adapter object
27374 getAdapter : function(){
27375 return this.adapter;
27379 * Set the adapter this SplitBar uses
27380 * @param {Object} adapter A SplitBar adapter object
27382 setAdapter : function(adapter){
27383 this.adapter = adapter;
27384 this.adapter.init(this);
27388 * Gets the minimum size for the resizing element
27389 * @return {Number} The minimum size
27391 getMinimumSize : function(){
27392 return this.minSize;
27396 * Sets the minimum size for the resizing element
27397 * @param {Number} minSize The minimum size
27399 setMinimumSize : function(minSize){
27400 this.minSize = minSize;
27404 * Gets the maximum size for the resizing element
27405 * @return {Number} The maximum size
27407 getMaximumSize : function(){
27408 return this.maxSize;
27412 * Sets the maximum size for the resizing element
27413 * @param {Number} maxSize The maximum size
27415 setMaximumSize : function(maxSize){
27416 this.maxSize = maxSize;
27420 * Sets the initialize size for the resizing element
27421 * @param {Number} size The initial size
27423 setCurrentSize : function(size){
27424 var oldAnimate = this.animate;
27425 this.animate = false;
27426 this.adapter.setElementSize(this, size);
27427 this.animate = oldAnimate;
27431 * Destroy this splitbar.
27432 * @param {Boolean} removeEl True to remove the element
27434 destroy : function(removeEl){
27436 this.shim.remove();
27439 this.proxy.parentNode.removeChild(this.proxy);
27447 * @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.
27449 Roo.SplitBar.createProxy = function(dir){
27450 var proxy = new Roo.Element(document.createElement("div"));
27451 proxy.unselectable();
27452 var cls = 'x-splitbar-proxy';
27453 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
27454 document.body.appendChild(proxy.dom);
27459 * @class Roo.SplitBar.BasicLayoutAdapter
27460 * Default Adapter. It assumes the splitter and resizing element are not positioned
27461 * elements and only gets/sets the width of the element. Generally used for table based layouts.
27463 Roo.SplitBar.BasicLayoutAdapter = function(){
27466 Roo.SplitBar.BasicLayoutAdapter.prototype = {
27467 // do nothing for now
27468 init : function(s){
27472 * Called before drag operations to get the current size of the resizing element.
27473 * @param {Roo.SplitBar} s The SplitBar using this adapter
27475 getElementSize : function(s){
27476 if(s.orientation == Roo.SplitBar.HORIZONTAL){
27477 return s.resizingEl.getWidth();
27479 return s.resizingEl.getHeight();
27484 * Called after drag operations to set the size of the resizing element.
27485 * @param {Roo.SplitBar} s The SplitBar using this adapter
27486 * @param {Number} newSize The new size to set
27487 * @param {Function} onComplete A function to be invoked when resizing is complete
27489 setElementSize : function(s, newSize, onComplete){
27490 if(s.orientation == Roo.SplitBar.HORIZONTAL){
27492 s.resizingEl.setWidth(newSize);
27494 onComplete(s, newSize);
27497 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
27502 s.resizingEl.setHeight(newSize);
27504 onComplete(s, newSize);
27507 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
27514 *@class Roo.SplitBar.AbsoluteLayoutAdapter
27515 * @extends Roo.SplitBar.BasicLayoutAdapter
27516 * Adapter that moves the splitter element to align with the resized sizing element.
27517 * Used with an absolute positioned SplitBar.
27518 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
27519 * document.body, make sure you assign an id to the body element.
27521 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
27522 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
27523 this.container = Roo.get(container);
27526 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
27527 init : function(s){
27528 this.basic.init(s);
27531 getElementSize : function(s){
27532 return this.basic.getElementSize(s);
27535 setElementSize : function(s, newSize, onComplete){
27536 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
27539 moveSplitter : function(s){
27540 var yes = Roo.SplitBar;
27541 switch(s.placement){
27543 s.el.setX(s.resizingEl.getRight());
27546 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
27549 s.el.setY(s.resizingEl.getBottom());
27552 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
27559 * Orientation constant - Create a vertical SplitBar
27563 Roo.SplitBar.VERTICAL = 1;
27566 * Orientation constant - Create a horizontal SplitBar
27570 Roo.SplitBar.HORIZONTAL = 2;
27573 * Placement constant - The resizing element is to the left of the splitter element
27577 Roo.SplitBar.LEFT = 1;
27580 * Placement constant - The resizing element is to the right of the splitter element
27584 Roo.SplitBar.RIGHT = 2;
27587 * Placement constant - The resizing element is positioned above the splitter element
27591 Roo.SplitBar.TOP = 3;
27594 * Placement constant - The resizing element is positioned under splitter element
27598 Roo.SplitBar.BOTTOM = 4;
27601 * Ext JS Library 1.1.1
27602 * Copyright(c) 2006-2007, Ext JS, LLC.
27604 * Originally Released Under LGPL - original licence link has changed is not relivant.
27607 * <script type="text/javascript">
27612 * @extends Roo.util.Observable
27613 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
27614 * This class also supports single and multi selection modes. <br>
27615 * Create a data model bound view:
27617 var store = new Roo.data.Store(...);
27619 var view = new Roo.View({
27621 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
27623 singleSelect: true,
27624 selectedClass: "ydataview-selected",
27628 // listen for node click?
27629 view.on("click", function(vw, index, node, e){
27630 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
27634 dataModel.load("foobar.xml");
27636 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
27638 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
27639 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
27641 * Note: old style constructor is still suported (container, template, config)
27644 * Create a new View
27645 * @param {Object} config The config object
27648 Roo.View = function(config, depreciated_tpl, depreciated_config){
27650 this.parent = false;
27652 if (typeof(depreciated_tpl) == 'undefined') {
27653 // new way.. - universal constructor.
27654 Roo.apply(this, config);
27655 this.el = Roo.get(this.el);
27658 this.el = Roo.get(config);
27659 this.tpl = depreciated_tpl;
27660 Roo.apply(this, depreciated_config);
27662 this.wrapEl = this.el.wrap().wrap();
27663 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
27666 if(typeof(this.tpl) == "string"){
27667 this.tpl = new Roo.Template(this.tpl);
27669 // support xtype ctors..
27670 this.tpl = new Roo.factory(this.tpl, Roo);
27674 this.tpl.compile();
27679 * @event beforeclick
27680 * Fires before a click is processed. Returns false to cancel the default action.
27681 * @param {Roo.View} this
27682 * @param {Number} index The index of the target node
27683 * @param {HTMLElement} node The target node
27684 * @param {Roo.EventObject} e The raw event object
27686 "beforeclick" : true,
27689 * Fires when a template node is clicked.
27690 * @param {Roo.View} this
27691 * @param {Number} index The index of the target node
27692 * @param {HTMLElement} node The target node
27693 * @param {Roo.EventObject} e The raw event object
27698 * Fires when a template node is double clicked.
27699 * @param {Roo.View} this
27700 * @param {Number} index The index of the target node
27701 * @param {HTMLElement} node The target node
27702 * @param {Roo.EventObject} e The raw event object
27706 * @event contextmenu
27707 * Fires when a template node is right clicked.
27708 * @param {Roo.View} this
27709 * @param {Number} index The index of the target node
27710 * @param {HTMLElement} node The target node
27711 * @param {Roo.EventObject} e The raw event object
27713 "contextmenu" : true,
27715 * @event selectionchange
27716 * Fires when the selected nodes change.
27717 * @param {Roo.View} this
27718 * @param {Array} selections Array of the selected nodes
27720 "selectionchange" : true,
27723 * @event beforeselect
27724 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
27725 * @param {Roo.View} this
27726 * @param {HTMLElement} node The node to be selected
27727 * @param {Array} selections Array of currently selected nodes
27729 "beforeselect" : true,
27731 * @event preparedata
27732 * Fires on every row to render, to allow you to change the data.
27733 * @param {Roo.View} this
27734 * @param {Object} data to be rendered (change this)
27736 "preparedata" : true
27744 "click": this.onClick,
27745 "dblclick": this.onDblClick,
27746 "contextmenu": this.onContextMenu,
27750 this.selections = [];
27752 this.cmp = new Roo.CompositeElementLite([]);
27754 this.store = Roo.factory(this.store, Roo.data);
27755 this.setStore(this.store, true);
27758 if ( this.footer && this.footer.xtype) {
27760 var fctr = this.wrapEl.appendChild(document.createElement("div"));
27762 this.footer.dataSource = this.store;
27763 this.footer.container = fctr;
27764 this.footer = Roo.factory(this.footer, Roo);
27765 fctr.insertFirst(this.el);
27767 // this is a bit insane - as the paging toolbar seems to detach the el..
27768 // dom.parentNode.parentNode.parentNode
27769 // they get detached?
27773 Roo.View.superclass.constructor.call(this);
27778 Roo.extend(Roo.View, Roo.util.Observable, {
27781 * @cfg {Roo.data.Store} store Data store to load data from.
27786 * @cfg {String|Roo.Element} el The container element.
27791 * @cfg {String|Roo.Template} tpl The template used by this View
27795 * @cfg {String} dataName the named area of the template to use as the data area
27796 * Works with domtemplates roo-name="name"
27800 * @cfg {String} selectedClass The css class to add to selected nodes
27802 selectedClass : "x-view-selected",
27804 * @cfg {String} emptyText The empty text to show when nothing is loaded.
27809 * @cfg {String} text to display on mask (default Loading)
27813 * @cfg {Boolean} multiSelect Allow multiple selection
27815 multiSelect : false,
27817 * @cfg {Boolean} singleSelect Allow single selection
27819 singleSelect: false,
27822 * @cfg {Boolean} toggleSelect - selecting
27824 toggleSelect : false,
27827 * @cfg {Boolean} tickable - selecting
27832 * Returns the element this view is bound to.
27833 * @return {Roo.Element}
27835 getEl : function(){
27836 return this.wrapEl;
27842 * Refreshes the view. - called by datachanged on the store. - do not call directly.
27844 refresh : function(){
27845 //Roo.log('refresh');
27848 // if we are using something like 'domtemplate', then
27849 // the what gets used is:
27850 // t.applySubtemplate(NAME, data, wrapping data..)
27851 // the outer template then get' applied with
27852 // the store 'extra data'
27853 // and the body get's added to the
27854 // roo-name="data" node?
27855 // <span class='roo-tpl-{name}'></span> ?????
27859 this.clearSelections();
27860 this.el.update("");
27862 var records = this.store.getRange();
27863 if(records.length < 1) {
27865 // is this valid?? = should it render a template??
27867 this.el.update(this.emptyText);
27871 if (this.dataName) {
27872 this.el.update(t.apply(this.store.meta)); //????
27873 el = this.el.child('.roo-tpl-' + this.dataName);
27876 for(var i = 0, len = records.length; i < len; i++){
27877 var data = this.prepareData(records[i].data, i, records[i]);
27878 this.fireEvent("preparedata", this, data, i, records[i]);
27880 var d = Roo.apply({}, data);
27883 Roo.apply(d, {'roo-id' : Roo.id()});
27887 Roo.each(this.parent.item, function(item){
27888 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
27891 Roo.apply(d, {'roo-data-checked' : 'checked'});
27895 html[html.length] = Roo.util.Format.trim(
27897 t.applySubtemplate(this.dataName, d, this.store.meta) :
27904 el.update(html.join(""));
27905 this.nodes = el.dom.childNodes;
27906 this.updateIndexes(0);
27911 * Function to override to reformat the data that is sent to
27912 * the template for each node.
27913 * DEPRICATED - use the preparedata event handler.
27914 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
27915 * a JSON object for an UpdateManager bound view).
27917 prepareData : function(data, index, record)
27919 this.fireEvent("preparedata", this, data, index, record);
27923 onUpdate : function(ds, record){
27924 // Roo.log('on update');
27925 this.clearSelections();
27926 var index = this.store.indexOf(record);
27927 var n = this.nodes[index];
27928 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
27929 n.parentNode.removeChild(n);
27930 this.updateIndexes(index, index);
27936 onAdd : function(ds, records, index)
27938 //Roo.log(['on Add', ds, records, index] );
27939 this.clearSelections();
27940 if(this.nodes.length == 0){
27944 var n = this.nodes[index];
27945 for(var i = 0, len = records.length; i < len; i++){
27946 var d = this.prepareData(records[i].data, i, records[i]);
27948 this.tpl.insertBefore(n, d);
27951 this.tpl.append(this.el, d);
27954 this.updateIndexes(index);
27957 onRemove : function(ds, record, index){
27958 // Roo.log('onRemove');
27959 this.clearSelections();
27960 var el = this.dataName ?
27961 this.el.child('.roo-tpl-' + this.dataName) :
27964 el.dom.removeChild(this.nodes[index]);
27965 this.updateIndexes(index);
27969 * Refresh an individual node.
27970 * @param {Number} index
27972 refreshNode : function(index){
27973 this.onUpdate(this.store, this.store.getAt(index));
27976 updateIndexes : function(startIndex, endIndex){
27977 var ns = this.nodes;
27978 startIndex = startIndex || 0;
27979 endIndex = endIndex || ns.length - 1;
27980 for(var i = startIndex; i <= endIndex; i++){
27981 ns[i].nodeIndex = i;
27986 * Changes the data store this view uses and refresh the view.
27987 * @param {Store} store
27989 setStore : function(store, initial){
27990 if(!initial && this.store){
27991 this.store.un("datachanged", this.refresh);
27992 this.store.un("add", this.onAdd);
27993 this.store.un("remove", this.onRemove);
27994 this.store.un("update", this.onUpdate);
27995 this.store.un("clear", this.refresh);
27996 this.store.un("beforeload", this.onBeforeLoad);
27997 this.store.un("load", this.onLoad);
27998 this.store.un("loadexception", this.onLoad);
28002 store.on("datachanged", this.refresh, this);
28003 store.on("add", this.onAdd, this);
28004 store.on("remove", this.onRemove, this);
28005 store.on("update", this.onUpdate, this);
28006 store.on("clear", this.refresh, this);
28007 store.on("beforeload", this.onBeforeLoad, this);
28008 store.on("load", this.onLoad, this);
28009 store.on("loadexception", this.onLoad, this);
28017 * onbeforeLoad - masks the loading area.
28020 onBeforeLoad : function(store,opts)
28022 //Roo.log('onBeforeLoad');
28024 this.el.update("");
28026 this.el.mask(this.mask ? this.mask : "Loading" );
28028 onLoad : function ()
28035 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
28036 * @param {HTMLElement} node
28037 * @return {HTMLElement} The template node
28039 findItemFromChild : function(node){
28040 var el = this.dataName ?
28041 this.el.child('.roo-tpl-' + this.dataName,true) :
28044 if(!node || node.parentNode == el){
28047 var p = node.parentNode;
28048 while(p && p != el){
28049 if(p.parentNode == el){
28058 onClick : function(e){
28059 var item = this.findItemFromChild(e.getTarget());
28061 var index = this.indexOf(item);
28062 if(this.onItemClick(item, index, e) !== false){
28063 this.fireEvent("click", this, index, item, e);
28066 this.clearSelections();
28071 onContextMenu : function(e){
28072 var item = this.findItemFromChild(e.getTarget());
28074 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
28079 onDblClick : function(e){
28080 var item = this.findItemFromChild(e.getTarget());
28082 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
28086 onItemClick : function(item, index, e)
28088 if(this.fireEvent("beforeclick", this, index, item, e) === false){
28091 if (this.toggleSelect) {
28092 var m = this.isSelected(item) ? 'unselect' : 'select';
28095 _t[m](item, true, false);
28098 if(this.multiSelect || this.singleSelect){
28099 if(this.multiSelect && e.shiftKey && this.lastSelection){
28100 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
28102 this.select(item, this.multiSelect && e.ctrlKey);
28103 this.lastSelection = item;
28106 if(!this.tickable){
28107 e.preventDefault();
28115 * Get the number of selected nodes.
28118 getSelectionCount : function(){
28119 return this.selections.length;
28123 * Get the currently selected nodes.
28124 * @return {Array} An array of HTMLElements
28126 getSelectedNodes : function(){
28127 return this.selections;
28131 * Get the indexes of the selected nodes.
28134 getSelectedIndexes : function(){
28135 var indexes = [], s = this.selections;
28136 for(var i = 0, len = s.length; i < len; i++){
28137 indexes.push(s[i].nodeIndex);
28143 * Clear all selections
28144 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
28146 clearSelections : function(suppressEvent){
28147 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
28148 this.cmp.elements = this.selections;
28149 this.cmp.removeClass(this.selectedClass);
28150 this.selections = [];
28151 if(!suppressEvent){
28152 this.fireEvent("selectionchange", this, this.selections);
28158 * Returns true if the passed node is selected
28159 * @param {HTMLElement/Number} node The node or node index
28160 * @return {Boolean}
28162 isSelected : function(node){
28163 var s = this.selections;
28167 node = this.getNode(node);
28168 return s.indexOf(node) !== -1;
28173 * @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
28174 * @param {Boolean} keepExisting (optional) true to keep existing selections
28175 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
28177 select : function(nodeInfo, keepExisting, suppressEvent){
28178 if(nodeInfo instanceof Array){
28180 this.clearSelections(true);
28182 for(var i = 0, len = nodeInfo.length; i < len; i++){
28183 this.select(nodeInfo[i], true, true);
28187 var node = this.getNode(nodeInfo);
28188 if(!node || this.isSelected(node)){
28189 return; // already selected.
28192 this.clearSelections(true);
28195 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
28196 Roo.fly(node).addClass(this.selectedClass);
28197 this.selections.push(node);
28198 if(!suppressEvent){
28199 this.fireEvent("selectionchange", this, this.selections);
28207 * @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
28208 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
28209 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
28211 unselect : function(nodeInfo, keepExisting, suppressEvent)
28213 if(nodeInfo instanceof Array){
28214 Roo.each(this.selections, function(s) {
28215 this.unselect(s, nodeInfo);
28219 var node = this.getNode(nodeInfo);
28220 if(!node || !this.isSelected(node)){
28221 //Roo.log("not selected");
28222 return; // not selected.
28226 Roo.each(this.selections, function(s) {
28228 Roo.fly(node).removeClass(this.selectedClass);
28235 this.selections= ns;
28236 this.fireEvent("selectionchange", this, this.selections);
28240 * Gets a template node.
28241 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
28242 * @return {HTMLElement} The node or null if it wasn't found
28244 getNode : function(nodeInfo){
28245 if(typeof nodeInfo == "string"){
28246 return document.getElementById(nodeInfo);
28247 }else if(typeof nodeInfo == "number"){
28248 return this.nodes[nodeInfo];
28254 * Gets a range template nodes.
28255 * @param {Number} startIndex
28256 * @param {Number} endIndex
28257 * @return {Array} An array of nodes
28259 getNodes : function(start, end){
28260 var ns = this.nodes;
28261 start = start || 0;
28262 end = typeof end == "undefined" ? ns.length - 1 : end;
28265 for(var i = start; i <= end; i++){
28269 for(var i = start; i >= end; i--){
28277 * Finds the index of the passed node
28278 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
28279 * @return {Number} The index of the node or -1
28281 indexOf : function(node){
28282 node = this.getNode(node);
28283 if(typeof node.nodeIndex == "number"){
28284 return node.nodeIndex;
28286 var ns = this.nodes;
28287 for(var i = 0, len = ns.length; i < len; i++){
28297 * Ext JS Library 1.1.1
28298 * Copyright(c) 2006-2007, Ext JS, LLC.
28300 * Originally Released Under LGPL - original licence link has changed is not relivant.
28303 * <script type="text/javascript">
28307 * @class Roo.JsonView
28308 * @extends Roo.View
28309 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
28311 var view = new Roo.JsonView({
28312 container: "my-element",
28313 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
28318 // listen for node click?
28319 view.on("click", function(vw, index, node, e){
28320 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
28323 // direct load of JSON data
28324 view.load("foobar.php");
28326 // Example from my blog list
28327 var tpl = new Roo.Template(
28328 '<div class="entry">' +
28329 '<a class="entry-title" href="{link}">{title}</a>' +
28330 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
28331 "</div><hr />"
28334 var moreView = new Roo.JsonView({
28335 container : "entry-list",
28339 moreView.on("beforerender", this.sortEntries, this);
28341 url: "/blog/get-posts.php",
28342 params: "allposts=true",
28343 text: "Loading Blog Entries..."
28347 * Note: old code is supported with arguments : (container, template, config)
28351 * Create a new JsonView
28353 * @param {Object} config The config object
28356 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
28359 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
28361 var um = this.el.getUpdateManager();
28362 um.setRenderer(this);
28363 um.on("update", this.onLoad, this);
28364 um.on("failure", this.onLoadException, this);
28367 * @event beforerender
28368 * Fires before rendering of the downloaded JSON data.
28369 * @param {Roo.JsonView} this
28370 * @param {Object} data The JSON data loaded
28374 * Fires when data is loaded.
28375 * @param {Roo.JsonView} this
28376 * @param {Object} data The JSON data loaded
28377 * @param {Object} response The raw Connect response object
28380 * @event loadexception
28381 * Fires when loading fails.
28382 * @param {Roo.JsonView} this
28383 * @param {Object} response The raw Connect response object
28386 'beforerender' : true,
28388 'loadexception' : true
28391 Roo.extend(Roo.JsonView, Roo.View, {
28393 * @type {String} The root property in the loaded JSON object that contains the data
28398 * Refreshes the view.
28400 refresh : function(){
28401 this.clearSelections();
28402 this.el.update("");
28404 var o = this.jsonData;
28405 if(o && o.length > 0){
28406 for(var i = 0, len = o.length; i < len; i++){
28407 var data = this.prepareData(o[i], i, o);
28408 html[html.length] = this.tpl.apply(data);
28411 html.push(this.emptyText);
28413 this.el.update(html.join(""));
28414 this.nodes = this.el.dom.childNodes;
28415 this.updateIndexes(0);
28419 * 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.
28420 * @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:
28423 url: "your-url.php",
28424 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
28425 callback: yourFunction,
28426 scope: yourObject, //(optional scope)
28429 text: "Loading...",
28434 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
28435 * 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.
28436 * @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}
28437 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
28438 * @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.
28441 var um = this.el.getUpdateManager();
28442 um.update.apply(um, arguments);
28445 // note - render is a standard framework call...
28446 // using it for the response is really flaky... - it's called by UpdateManager normally, except when called by the XComponent/addXtype.
28447 render : function(el, response){
28449 this.clearSelections();
28450 this.el.update("");
28453 if (response != '') {
28454 o = Roo.util.JSON.decode(response.responseText);
28457 o = o[this.jsonRoot];
28463 * The current JSON data or null
28466 this.beforeRender();
28471 * Get the number of records in the current JSON dataset
28474 getCount : function(){
28475 return this.jsonData ? this.jsonData.length : 0;
28479 * Returns the JSON object for the specified node(s)
28480 * @param {HTMLElement/Array} node The node or an array of nodes
28481 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
28482 * you get the JSON object for the node
28484 getNodeData : function(node){
28485 if(node instanceof Array){
28487 for(var i = 0, len = node.length; i < len; i++){
28488 data.push(this.getNodeData(node[i]));
28492 return this.jsonData[this.indexOf(node)] || null;
28495 beforeRender : function(){
28496 this.snapshot = this.jsonData;
28498 this.sort.apply(this, this.sortInfo);
28500 this.fireEvent("beforerender", this, this.jsonData);
28503 onLoad : function(el, o){
28504 this.fireEvent("load", this, this.jsonData, o);
28507 onLoadException : function(el, o){
28508 this.fireEvent("loadexception", this, o);
28512 * Filter the data by a specific property.
28513 * @param {String} property A property on your JSON objects
28514 * @param {String/RegExp} value Either string that the property values
28515 * should start with, or a RegExp to test against the property
28517 filter : function(property, value){
28520 var ss = this.snapshot;
28521 if(typeof value == "string"){
28522 var vlen = value.length;
28524 this.clearFilter();
28527 value = value.toLowerCase();
28528 for(var i = 0, len = ss.length; i < len; i++){
28530 if(o[property].substr(0, vlen).toLowerCase() == value){
28534 } else if(value.exec){ // regex?
28535 for(var i = 0, len = ss.length; i < len; i++){
28537 if(value.test(o[property])){
28544 this.jsonData = data;
28550 * Filter by a function. The passed function will be called with each
28551 * object in the current dataset. If the function returns true the value is kept,
28552 * otherwise it is filtered.
28553 * @param {Function} fn
28554 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
28556 filterBy : function(fn, scope){
28559 var ss = this.snapshot;
28560 for(var i = 0, len = ss.length; i < len; i++){
28562 if(fn.call(scope || this, o)){
28566 this.jsonData = data;
28572 * Clears the current filter.
28574 clearFilter : function(){
28575 if(this.snapshot && this.jsonData != this.snapshot){
28576 this.jsonData = this.snapshot;
28583 * Sorts the data for this view and refreshes it.
28584 * @param {String} property A property on your JSON objects to sort on
28585 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
28586 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
28588 sort : function(property, dir, sortType){
28589 this.sortInfo = Array.prototype.slice.call(arguments, 0);
28592 var dsc = dir && dir.toLowerCase() == "desc";
28593 var f = function(o1, o2){
28594 var v1 = sortType ? sortType(o1[p]) : o1[p];
28595 var v2 = sortType ? sortType(o2[p]) : o2[p];
28598 return dsc ? +1 : -1;
28599 } else if(v1 > v2){
28600 return dsc ? -1 : +1;
28605 this.jsonData.sort(f);
28607 if(this.jsonData != this.snapshot){
28608 this.snapshot.sort(f);
28614 * Ext JS Library 1.1.1
28615 * Copyright(c) 2006-2007, Ext JS, LLC.
28617 * Originally Released Under LGPL - original licence link has changed is not relivant.
28620 * <script type="text/javascript">
28625 * @class Roo.ColorPalette
28626 * @extends Roo.Component
28627 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
28628 * Here's an example of typical usage:
28630 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
28631 cp.render('my-div');
28633 cp.on('select', function(palette, selColor){
28634 // do something with selColor
28638 * Create a new ColorPalette
28639 * @param {Object} config The config object
28641 Roo.ColorPalette = function(config){
28642 Roo.ColorPalette.superclass.constructor.call(this, config);
28646 * Fires when a color is selected
28647 * @param {ColorPalette} this
28648 * @param {String} color The 6-digit color hex code (without the # symbol)
28654 this.on("select", this.handler, this.scope, true);
28657 Roo.extend(Roo.ColorPalette, Roo.Component, {
28659 * @cfg {String} itemCls
28660 * The CSS class to apply to the containing element (defaults to "x-color-palette")
28662 itemCls : "x-color-palette",
28664 * @cfg {String} value
28665 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
28666 * the hex codes are case-sensitive.
28669 clickEvent:'click',
28671 ctype: "Roo.ColorPalette",
28674 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
28676 allowReselect : false,
28679 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
28680 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
28681 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
28682 * of colors with the width setting until the box is symmetrical.</p>
28683 * <p>You can override individual colors if needed:</p>
28685 var cp = new Roo.ColorPalette();
28686 cp.colors[0] = "FF0000"; // change the first box to red
28689 Or you can provide a custom array of your own for complete control:
28691 var cp = new Roo.ColorPalette();
28692 cp.colors = ["000000", "993300", "333300"];
28697 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
28698 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
28699 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
28700 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
28701 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
28705 onRender : function(container, position){
28706 var t = new Roo.MasterTemplate(
28707 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
28709 var c = this.colors;
28710 for(var i = 0, len = c.length; i < len; i++){
28713 var el = document.createElement("div");
28714 el.className = this.itemCls;
28716 container.dom.insertBefore(el, position);
28717 this.el = Roo.get(el);
28718 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
28719 if(this.clickEvent != 'click'){
28720 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
28725 afterRender : function(){
28726 Roo.ColorPalette.superclass.afterRender.call(this);
28728 var s = this.value;
28735 handleClick : function(e, t){
28736 e.preventDefault();
28737 if(!this.disabled){
28738 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
28739 this.select(c.toUpperCase());
28744 * Selects the specified color in the palette (fires the select event)
28745 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
28747 select : function(color){
28748 color = color.replace("#", "");
28749 if(color != this.value || this.allowReselect){
28752 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
28754 el.child("a.color-"+color).addClass("x-color-palette-sel");
28755 this.value = color;
28756 this.fireEvent("select", this, color);
28761 * Ext JS Library 1.1.1
28762 * Copyright(c) 2006-2007, Ext JS, LLC.
28764 * Originally Released Under LGPL - original licence link has changed is not relivant.
28767 * <script type="text/javascript">
28771 * @class Roo.DatePicker
28772 * @extends Roo.Component
28773 * Simple date picker class.
28775 * Create a new DatePicker
28776 * @param {Object} config The config object
28778 Roo.DatePicker = function(config){
28779 Roo.DatePicker.superclass.constructor.call(this, config);
28781 this.value = config && config.value ?
28782 config.value.clearTime() : new Date().clearTime();
28787 * Fires when a date is selected
28788 * @param {DatePicker} this
28789 * @param {Date} date The selected date
28793 * @event monthchange
28794 * Fires when the displayed month changes
28795 * @param {DatePicker} this
28796 * @param {Date} date The selected month
28798 'monthchange': true
28802 this.on("select", this.handler, this.scope || this);
28804 // build the disabledDatesRE
28805 if(!this.disabledDatesRE && this.disabledDates){
28806 var dd = this.disabledDates;
28808 for(var i = 0; i < dd.length; i++){
28810 if(i != dd.length-1) {
28814 this.disabledDatesRE = new RegExp(re + ")");
28818 Roo.extend(Roo.DatePicker, Roo.Component, {
28820 * @cfg {String} todayText
28821 * The text to display on the button that selects the current date (defaults to "Today")
28823 todayText : "Today",
28825 * @cfg {String} okText
28826 * The text to display on the ok button
28828 okText : " OK ", //   to give the user extra clicking room
28830 * @cfg {String} cancelText
28831 * The text to display on the cancel button
28833 cancelText : "Cancel",
28835 * @cfg {String} todayTip
28836 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
28838 todayTip : "{0} (Spacebar)",
28840 * @cfg {Date} minDate
28841 * Minimum allowable date (JavaScript date object, defaults to null)
28845 * @cfg {Date} maxDate
28846 * Maximum allowable date (JavaScript date object, defaults to null)
28850 * @cfg {String} minText
28851 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
28853 minText : "This date is before the minimum date",
28855 * @cfg {String} maxText
28856 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
28858 maxText : "This date is after the maximum date",
28860 * @cfg {String} format
28861 * The default date format string which can be overriden for localization support. The format must be
28862 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
28866 * @cfg {Array} disabledDays
28867 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
28869 disabledDays : null,
28871 * @cfg {String} disabledDaysText
28872 * The tooltip to display when the date falls on a disabled day (defaults to "")
28874 disabledDaysText : "",
28876 * @cfg {RegExp} disabledDatesRE
28877 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
28879 disabledDatesRE : null,
28881 * @cfg {String} disabledDatesText
28882 * The tooltip text to display when the date falls on a disabled date (defaults to "")
28884 disabledDatesText : "",
28886 * @cfg {Boolean} constrainToViewport
28887 * True to constrain the date picker to the viewport (defaults to true)
28889 constrainToViewport : true,
28891 * @cfg {Array} monthNames
28892 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
28894 monthNames : Date.monthNames,
28896 * @cfg {Array} dayNames
28897 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
28899 dayNames : Date.dayNames,
28901 * @cfg {String} nextText
28902 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
28904 nextText: 'Next Month (Control+Right)',
28906 * @cfg {String} prevText
28907 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
28909 prevText: 'Previous Month (Control+Left)',
28911 * @cfg {String} monthYearText
28912 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
28914 monthYearText: 'Choose a month (Control+Up/Down to move years)',
28916 * @cfg {Number} startDay
28917 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
28921 * @cfg {Bool} showClear
28922 * Show a clear button (usefull for date form elements that can be blank.)
28928 * Sets the value of the date field
28929 * @param {Date} value The date to set
28931 setValue : function(value){
28932 var old = this.value;
28934 if (typeof(value) == 'string') {
28936 value = Date.parseDate(value, this.format);
28939 value = new Date();
28942 this.value = value.clearTime(true);
28944 this.update(this.value);
28949 * Gets the current selected value of the date field
28950 * @return {Date} The selected date
28952 getValue : function(){
28957 focus : function(){
28959 this.update(this.activeDate);
28964 onRender : function(container, position){
28967 '<table cellspacing="0">',
28968 '<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>',
28969 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
28970 var dn = this.dayNames;
28971 for(var i = 0; i < 7; i++){
28972 var d = this.startDay+i;
28976 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
28978 m[m.length] = "</tr></thead><tbody><tr>";
28979 for(var i = 0; i < 42; i++) {
28980 if(i % 7 == 0 && i != 0){
28981 m[m.length] = "</tr><tr>";
28983 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
28985 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
28986 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
28988 var el = document.createElement("div");
28989 el.className = "x-date-picker";
28990 el.innerHTML = m.join("");
28992 container.dom.insertBefore(el, position);
28994 this.el = Roo.get(el);
28995 this.eventEl = Roo.get(el.firstChild);
28997 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
28998 handler: this.showPrevMonth,
29000 preventDefault:true,
29004 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
29005 handler: this.showNextMonth,
29007 preventDefault:true,
29011 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
29013 this.monthPicker = this.el.down('div.x-date-mp');
29014 this.monthPicker.enableDisplayMode('block');
29016 var kn = new Roo.KeyNav(this.eventEl, {
29017 "left" : function(e){
29019 this.showPrevMonth() :
29020 this.update(this.activeDate.add("d", -1));
29023 "right" : function(e){
29025 this.showNextMonth() :
29026 this.update(this.activeDate.add("d", 1));
29029 "up" : function(e){
29031 this.showNextYear() :
29032 this.update(this.activeDate.add("d", -7));
29035 "down" : function(e){
29037 this.showPrevYear() :
29038 this.update(this.activeDate.add("d", 7));
29041 "pageUp" : function(e){
29042 this.showNextMonth();
29045 "pageDown" : function(e){
29046 this.showPrevMonth();
29049 "enter" : function(e){
29050 e.stopPropagation();
29057 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
29059 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
29061 this.el.unselectable();
29063 this.cells = this.el.select("table.x-date-inner tbody td");
29064 this.textNodes = this.el.query("table.x-date-inner tbody span");
29066 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
29068 tooltip: this.monthYearText
29071 this.mbtn.on('click', this.showMonthPicker, this);
29072 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
29075 var today = (new Date()).dateFormat(this.format);
29077 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
29078 if (this.showClear) {
29079 baseTb.add( new Roo.Toolbar.Fill());
29082 text: String.format(this.todayText, today),
29083 tooltip: String.format(this.todayTip, today),
29084 handler: this.selectToday,
29088 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
29091 if (this.showClear) {
29093 baseTb.add( new Roo.Toolbar.Fill());
29096 cls: 'x-btn-icon x-btn-clear',
29097 handler: function() {
29099 this.fireEvent("select", this, '');
29109 this.update(this.value);
29112 createMonthPicker : function(){
29113 if(!this.monthPicker.dom.firstChild){
29114 var buf = ['<table border="0" cellspacing="0">'];
29115 for(var i = 0; i < 6; i++){
29117 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
29118 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
29120 '<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>' :
29121 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
29125 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
29127 '</button><button type="button" class="x-date-mp-cancel">',
29129 '</button></td></tr>',
29132 this.monthPicker.update(buf.join(''));
29133 this.monthPicker.on('click', this.onMonthClick, this);
29134 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
29136 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
29137 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
29139 this.mpMonths.each(function(m, a, i){
29142 m.dom.xmonth = 5 + Math.round(i * .5);
29144 m.dom.xmonth = Math.round((i-1) * .5);
29150 showMonthPicker : function(){
29151 this.createMonthPicker();
29152 var size = this.el.getSize();
29153 this.monthPicker.setSize(size);
29154 this.monthPicker.child('table').setSize(size);
29156 this.mpSelMonth = (this.activeDate || this.value).getMonth();
29157 this.updateMPMonth(this.mpSelMonth);
29158 this.mpSelYear = (this.activeDate || this.value).getFullYear();
29159 this.updateMPYear(this.mpSelYear);
29161 this.monthPicker.slideIn('t', {duration:.2});
29164 updateMPYear : function(y){
29166 var ys = this.mpYears.elements;
29167 for(var i = 1; i <= 10; i++){
29168 var td = ys[i-1], y2;
29170 y2 = y + Math.round(i * .5);
29171 td.firstChild.innerHTML = y2;
29174 y2 = y - (5-Math.round(i * .5));
29175 td.firstChild.innerHTML = y2;
29178 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
29182 updateMPMonth : function(sm){
29183 this.mpMonths.each(function(m, a, i){
29184 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
29188 selectMPMonth: function(m){
29192 onMonthClick : function(e, t){
29194 var el = new Roo.Element(t), pn;
29195 if(el.is('button.x-date-mp-cancel')){
29196 this.hideMonthPicker();
29198 else if(el.is('button.x-date-mp-ok')){
29199 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
29200 this.hideMonthPicker();
29202 else if(pn = el.up('td.x-date-mp-month', 2)){
29203 this.mpMonths.removeClass('x-date-mp-sel');
29204 pn.addClass('x-date-mp-sel');
29205 this.mpSelMonth = pn.dom.xmonth;
29207 else if(pn = el.up('td.x-date-mp-year', 2)){
29208 this.mpYears.removeClass('x-date-mp-sel');
29209 pn.addClass('x-date-mp-sel');
29210 this.mpSelYear = pn.dom.xyear;
29212 else if(el.is('a.x-date-mp-prev')){
29213 this.updateMPYear(this.mpyear-10);
29215 else if(el.is('a.x-date-mp-next')){
29216 this.updateMPYear(this.mpyear+10);
29220 onMonthDblClick : function(e, t){
29222 var el = new Roo.Element(t), pn;
29223 if(pn = el.up('td.x-date-mp-month', 2)){
29224 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
29225 this.hideMonthPicker();
29227 else if(pn = el.up('td.x-date-mp-year', 2)){
29228 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
29229 this.hideMonthPicker();
29233 hideMonthPicker : function(disableAnim){
29234 if(this.monthPicker){
29235 if(disableAnim === true){
29236 this.monthPicker.hide();
29238 this.monthPicker.slideOut('t', {duration:.2});
29244 showPrevMonth : function(e){
29245 this.update(this.activeDate.add("mo", -1));
29249 showNextMonth : function(e){
29250 this.update(this.activeDate.add("mo", 1));
29254 showPrevYear : function(){
29255 this.update(this.activeDate.add("y", -1));
29259 showNextYear : function(){
29260 this.update(this.activeDate.add("y", 1));
29264 handleMouseWheel : function(e){
29265 var delta = e.getWheelDelta();
29267 this.showPrevMonth();
29269 } else if(delta < 0){
29270 this.showNextMonth();
29276 handleDateClick : function(e, t){
29278 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
29279 this.setValue(new Date(t.dateValue));
29280 this.fireEvent("select", this, this.value);
29285 selectToday : function(){
29286 this.setValue(new Date().clearTime());
29287 this.fireEvent("select", this, this.value);
29291 update : function(date)
29293 var vd = this.activeDate;
29294 this.activeDate = date;
29296 var t = date.getTime();
29297 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
29298 this.cells.removeClass("x-date-selected");
29299 this.cells.each(function(c){
29300 if(c.dom.firstChild.dateValue == t){
29301 c.addClass("x-date-selected");
29302 setTimeout(function(){
29303 try{c.dom.firstChild.focus();}catch(e){}
29312 var days = date.getDaysInMonth();
29313 var firstOfMonth = date.getFirstDateOfMonth();
29314 var startingPos = firstOfMonth.getDay()-this.startDay;
29316 if(startingPos <= this.startDay){
29320 var pm = date.add("mo", -1);
29321 var prevStart = pm.getDaysInMonth()-startingPos;
29323 var cells = this.cells.elements;
29324 var textEls = this.textNodes;
29325 days += startingPos;
29327 // convert everything to numbers so it's fast
29328 var day = 86400000;
29329 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
29330 var today = new Date().clearTime().getTime();
29331 var sel = date.clearTime().getTime();
29332 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
29333 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
29334 var ddMatch = this.disabledDatesRE;
29335 var ddText = this.disabledDatesText;
29336 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
29337 var ddaysText = this.disabledDaysText;
29338 var format = this.format;
29340 var setCellClass = function(cal, cell){
29342 var t = d.getTime();
29343 cell.firstChild.dateValue = t;
29345 cell.className += " x-date-today";
29346 cell.title = cal.todayText;
29349 cell.className += " x-date-selected";
29350 setTimeout(function(){
29351 try{cell.firstChild.focus();}catch(e){}
29356 cell.className = " x-date-disabled";
29357 cell.title = cal.minText;
29361 cell.className = " x-date-disabled";
29362 cell.title = cal.maxText;
29366 if(ddays.indexOf(d.getDay()) != -1){
29367 cell.title = ddaysText;
29368 cell.className = " x-date-disabled";
29371 if(ddMatch && format){
29372 var fvalue = d.dateFormat(format);
29373 if(ddMatch.test(fvalue)){
29374 cell.title = ddText.replace("%0", fvalue);
29375 cell.className = " x-date-disabled";
29381 for(; i < startingPos; i++) {
29382 textEls[i].innerHTML = (++prevStart);
29383 d.setDate(d.getDate()+1);
29384 cells[i].className = "x-date-prevday";
29385 setCellClass(this, cells[i]);
29387 for(; i < days; i++){
29388 intDay = i - startingPos + 1;
29389 textEls[i].innerHTML = (intDay);
29390 d.setDate(d.getDate()+1);
29391 cells[i].className = "x-date-active";
29392 setCellClass(this, cells[i]);
29395 for(; i < 42; i++) {
29396 textEls[i].innerHTML = (++extraDays);
29397 d.setDate(d.getDate()+1);
29398 cells[i].className = "x-date-nextday";
29399 setCellClass(this, cells[i]);
29402 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
29403 this.fireEvent('monthchange', this, date);
29405 if(!this.internalRender){
29406 var main = this.el.dom.firstChild;
29407 var w = main.offsetWidth;
29408 this.el.setWidth(w + this.el.getBorderWidth("lr"));
29409 Roo.fly(main).setWidth(w);
29410 this.internalRender = true;
29411 // opera does not respect the auto grow header center column
29412 // then, after it gets a width opera refuses to recalculate
29413 // without a second pass
29414 if(Roo.isOpera && !this.secondPass){
29415 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
29416 this.secondPass = true;
29417 this.update.defer(10, this, [date]);
29425 * Ext JS Library 1.1.1
29426 * Copyright(c) 2006-2007, Ext JS, LLC.
29428 * Originally Released Under LGPL - original licence link has changed is not relivant.
29431 * <script type="text/javascript">
29434 * @class Roo.TabPanel
29435 * @extends Roo.util.Observable
29436 * A lightweight tab container.
29440 // basic tabs 1, built from existing content
29441 var tabs = new Roo.TabPanel("tabs1");
29442 tabs.addTab("script", "View Script");
29443 tabs.addTab("markup", "View Markup");
29444 tabs.activate("script");
29446 // more advanced tabs, built from javascript
29447 var jtabs = new Roo.TabPanel("jtabs");
29448 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
29450 // set up the UpdateManager
29451 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
29452 var updater = tab2.getUpdateManager();
29453 updater.setDefaultUrl("ajax1.htm");
29454 tab2.on('activate', updater.refresh, updater, true);
29456 // Use setUrl for Ajax loading
29457 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
29458 tab3.setUrl("ajax2.htm", null, true);
29461 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
29464 jtabs.activate("jtabs-1");
29467 * Create a new TabPanel.
29468 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
29469 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
29471 Roo.TabPanel = function(container, config){
29473 * The container element for this TabPanel.
29474 * @type Roo.Element
29476 this.el = Roo.get(container, true);
29478 if(typeof config == "boolean"){
29479 this.tabPosition = config ? "bottom" : "top";
29481 Roo.apply(this, config);
29484 if(this.tabPosition == "bottom"){
29485 this.bodyEl = Roo.get(this.createBody(this.el.dom));
29486 this.el.addClass("x-tabs-bottom");
29488 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
29489 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
29490 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
29492 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
29494 if(this.tabPosition != "bottom"){
29495 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
29496 * @type Roo.Element
29498 this.bodyEl = Roo.get(this.createBody(this.el.dom));
29499 this.el.addClass("x-tabs-top");
29503 this.bodyEl.setStyle("position", "relative");
29505 this.active = null;
29506 this.activateDelegate = this.activate.createDelegate(this);
29511 * Fires when the active tab changes
29512 * @param {Roo.TabPanel} this
29513 * @param {Roo.TabPanelItem} activePanel The new active tab
29517 * @event beforetabchange
29518 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
29519 * @param {Roo.TabPanel} this
29520 * @param {Object} e Set cancel to true on this object to cancel the tab change
29521 * @param {Roo.TabPanelItem} tab The tab being changed to
29523 "beforetabchange" : true
29526 Roo.EventManager.onWindowResize(this.onResize, this);
29527 this.cpad = this.el.getPadding("lr");
29528 this.hiddenCount = 0;
29531 // toolbar on the tabbar support...
29532 if (this.toolbar) {
29533 var tcfg = this.toolbar;
29534 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
29535 this.toolbar = new Roo.Toolbar(tcfg);
29536 if (Roo.isSafari) {
29537 var tbl = tcfg.container.child('table', true);
29538 tbl.setAttribute('width', '100%');
29545 Roo.TabPanel.superclass.constructor.call(this);
29548 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
29550 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
29552 tabPosition : "top",
29554 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
29556 currentTabWidth : 0,
29558 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
29562 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
29566 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
29568 preferredTabWidth : 175,
29570 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
29572 resizeTabs : false,
29574 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
29576 monitorResize : true,
29578 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
29583 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
29584 * @param {String} id The id of the div to use <b>or create</b>
29585 * @param {String} text The text for the tab
29586 * @param {String} content (optional) Content to put in the TabPanelItem body
29587 * @param {Boolean} closable (optional) True to create a close icon on the tab
29588 * @return {Roo.TabPanelItem} The created TabPanelItem
29590 addTab : function(id, text, content, closable){
29591 var item = new Roo.TabPanelItem(this, id, text, closable);
29592 this.addTabItem(item);
29594 item.setContent(content);
29600 * Returns the {@link Roo.TabPanelItem} with the specified id/index
29601 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
29602 * @return {Roo.TabPanelItem}
29604 getTab : function(id){
29605 return this.items[id];
29609 * Hides the {@link Roo.TabPanelItem} with the specified id/index
29610 * @param {String/Number} id The id or index of the TabPanelItem to hide.
29612 hideTab : function(id){
29613 var t = this.items[id];
29616 this.hiddenCount++;
29617 this.autoSizeTabs();
29622 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
29623 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
29625 unhideTab : function(id){
29626 var t = this.items[id];
29628 t.setHidden(false);
29629 this.hiddenCount--;
29630 this.autoSizeTabs();
29635 * Adds an existing {@link Roo.TabPanelItem}.
29636 * @param {Roo.TabPanelItem} item The TabPanelItem to add
29638 addTabItem : function(item){
29639 this.items[item.id] = item;
29640 this.items.push(item);
29641 if(this.resizeTabs){
29642 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
29643 this.autoSizeTabs();
29650 * Removes a {@link Roo.TabPanelItem}.
29651 * @param {String/Number} id The id or index of the TabPanelItem to remove.
29653 removeTab : function(id){
29654 var items = this.items;
29655 var tab = items[id];
29656 if(!tab) { return; }
29657 var index = items.indexOf(tab);
29658 if(this.active == tab && items.length > 1){
29659 var newTab = this.getNextAvailable(index);
29664 this.stripEl.dom.removeChild(tab.pnode.dom);
29665 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
29666 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
29668 items.splice(index, 1);
29669 delete this.items[tab.id];
29670 tab.fireEvent("close", tab);
29671 tab.purgeListeners();
29672 this.autoSizeTabs();
29675 getNextAvailable : function(start){
29676 var items = this.items;
29678 // look for a next tab that will slide over to
29679 // replace the one being removed
29680 while(index < items.length){
29681 var item = items[++index];
29682 if(item && !item.isHidden()){
29686 // if one isn't found select the previous tab (on the left)
29689 var item = items[--index];
29690 if(item && !item.isHidden()){
29698 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
29699 * @param {String/Number} id The id or index of the TabPanelItem to disable.
29701 disableTab : function(id){
29702 var tab = this.items[id];
29703 if(tab && this.active != tab){
29709 * Enables a {@link Roo.TabPanelItem} that is disabled.
29710 * @param {String/Number} id The id or index of the TabPanelItem to enable.
29712 enableTab : function(id){
29713 var tab = this.items[id];
29718 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
29719 * @param {String/Number} id The id or index of the TabPanelItem to activate.
29720 * @return {Roo.TabPanelItem} The TabPanelItem.
29722 activate : function(id){
29723 var tab = this.items[id];
29727 if(tab == this.active || tab.disabled){
29731 this.fireEvent("beforetabchange", this, e, tab);
29732 if(e.cancel !== true && !tab.disabled){
29734 this.active.hide();
29736 this.active = this.items[id];
29737 this.active.show();
29738 this.fireEvent("tabchange", this, this.active);
29744 * Gets the active {@link Roo.TabPanelItem}.
29745 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
29747 getActiveTab : function(){
29748 return this.active;
29752 * Updates the tab body element to fit the height of the container element
29753 * for overflow scrolling
29754 * @param {Number} targetHeight (optional) Override the starting height from the elements height
29756 syncHeight : function(targetHeight){
29757 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
29758 var bm = this.bodyEl.getMargins();
29759 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
29760 this.bodyEl.setHeight(newHeight);
29764 onResize : function(){
29765 if(this.monitorResize){
29766 this.autoSizeTabs();
29771 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
29773 beginUpdate : function(){
29774 this.updating = true;
29778 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
29780 endUpdate : function(){
29781 this.updating = false;
29782 this.autoSizeTabs();
29786 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
29788 autoSizeTabs : function(){
29789 var count = this.items.length;
29790 var vcount = count - this.hiddenCount;
29791 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
29794 var w = Math.max(this.el.getWidth() - this.cpad, 10);
29795 var availWidth = Math.floor(w / vcount);
29796 var b = this.stripBody;
29797 if(b.getWidth() > w){
29798 var tabs = this.items;
29799 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
29800 if(availWidth < this.minTabWidth){
29801 /*if(!this.sleft){ // incomplete scrolling code
29802 this.createScrollButtons();
29805 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
29808 if(this.currentTabWidth < this.preferredTabWidth){
29809 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
29815 * Returns the number of tabs in this TabPanel.
29818 getCount : function(){
29819 return this.items.length;
29823 * Resizes all the tabs to the passed width
29824 * @param {Number} The new width
29826 setTabWidth : function(width){
29827 this.currentTabWidth = width;
29828 for(var i = 0, len = this.items.length; i < len; i++) {
29829 if(!this.items[i].isHidden()) {
29830 this.items[i].setWidth(width);
29836 * Destroys this TabPanel
29837 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
29839 destroy : function(removeEl){
29840 Roo.EventManager.removeResizeListener(this.onResize, this);
29841 for(var i = 0, len = this.items.length; i < len; i++){
29842 this.items[i].purgeListeners();
29844 if(removeEl === true){
29845 this.el.update("");
29852 * @class Roo.TabPanelItem
29853 * @extends Roo.util.Observable
29854 * Represents an individual item (tab plus body) in a TabPanel.
29855 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
29856 * @param {String} id The id of this TabPanelItem
29857 * @param {String} text The text for the tab of this TabPanelItem
29858 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
29860 Roo.TabPanelItem = function(tabPanel, id, text, closable){
29862 * The {@link Roo.TabPanel} this TabPanelItem belongs to
29863 * @type Roo.TabPanel
29865 this.tabPanel = tabPanel;
29867 * The id for this TabPanelItem
29872 this.disabled = false;
29876 this.loaded = false;
29877 this.closable = closable;
29880 * The body element for this TabPanelItem.
29881 * @type Roo.Element
29883 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
29884 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
29885 this.bodyEl.setStyle("display", "block");
29886 this.bodyEl.setStyle("zoom", "1");
29889 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
29891 this.el = Roo.get(els.el, true);
29892 this.inner = Roo.get(els.inner, true);
29893 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
29894 this.pnode = Roo.get(els.el.parentNode, true);
29895 this.el.on("mousedown", this.onTabMouseDown, this);
29896 this.el.on("click", this.onTabClick, this);
29899 var c = Roo.get(els.close, true);
29900 c.dom.title = this.closeText;
29901 c.addClassOnOver("close-over");
29902 c.on("click", this.closeClick, this);
29908 * Fires when this tab becomes the active tab.
29909 * @param {Roo.TabPanel} tabPanel The parent TabPanel
29910 * @param {Roo.TabPanelItem} this
29914 * @event beforeclose
29915 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
29916 * @param {Roo.TabPanelItem} this
29917 * @param {Object} e Set cancel to true on this object to cancel the close.
29919 "beforeclose": true,
29922 * Fires when this tab is closed.
29923 * @param {Roo.TabPanelItem} this
29927 * @event deactivate
29928 * Fires when this tab is no longer the active tab.
29929 * @param {Roo.TabPanel} tabPanel The parent TabPanel
29930 * @param {Roo.TabPanelItem} this
29932 "deactivate" : true
29934 this.hidden = false;
29936 Roo.TabPanelItem.superclass.constructor.call(this);
29939 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
29940 purgeListeners : function(){
29941 Roo.util.Observable.prototype.purgeListeners.call(this);
29942 this.el.removeAllListeners();
29945 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
29948 this.pnode.addClass("on");
29951 this.tabPanel.stripWrap.repaint();
29953 this.fireEvent("activate", this.tabPanel, this);
29957 * Returns true if this tab is the active tab.
29958 * @return {Boolean}
29960 isActive : function(){
29961 return this.tabPanel.getActiveTab() == this;
29965 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
29968 this.pnode.removeClass("on");
29970 this.fireEvent("deactivate", this.tabPanel, this);
29973 hideAction : function(){
29974 this.bodyEl.hide();
29975 this.bodyEl.setStyle("position", "absolute");
29976 this.bodyEl.setLeft("-20000px");
29977 this.bodyEl.setTop("-20000px");
29980 showAction : function(){
29981 this.bodyEl.setStyle("position", "relative");
29982 this.bodyEl.setTop("");
29983 this.bodyEl.setLeft("");
29984 this.bodyEl.show();
29988 * Set the tooltip for the tab.
29989 * @param {String} tooltip The tab's tooltip
29991 setTooltip : function(text){
29992 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
29993 this.textEl.dom.qtip = text;
29994 this.textEl.dom.removeAttribute('title');
29996 this.textEl.dom.title = text;
30000 onTabClick : function(e){
30001 e.preventDefault();
30002 this.tabPanel.activate(this.id);
30005 onTabMouseDown : function(e){
30006 e.preventDefault();
30007 this.tabPanel.activate(this.id);
30010 getWidth : function(){
30011 return this.inner.getWidth();
30014 setWidth : function(width){
30015 var iwidth = width - this.pnode.getPadding("lr");
30016 this.inner.setWidth(iwidth);
30017 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
30018 this.pnode.setWidth(width);
30022 * Show or hide the tab
30023 * @param {Boolean} hidden True to hide or false to show.
30025 setHidden : function(hidden){
30026 this.hidden = hidden;
30027 this.pnode.setStyle("display", hidden ? "none" : "");
30031 * Returns true if this tab is "hidden"
30032 * @return {Boolean}
30034 isHidden : function(){
30035 return this.hidden;
30039 * Returns the text for this tab
30042 getText : function(){
30046 autoSize : function(){
30047 //this.el.beginMeasure();
30048 this.textEl.setWidth(1);
30050 * #2804 [new] Tabs in Roojs
30051 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
30053 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
30054 //this.el.endMeasure();
30058 * Sets the text for the tab (Note: this also sets the tooltip text)
30059 * @param {String} text The tab's text and tooltip
30061 setText : function(text){
30063 this.textEl.update(text);
30064 this.setTooltip(text);
30065 if(!this.tabPanel.resizeTabs){
30070 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
30072 activate : function(){
30073 this.tabPanel.activate(this.id);
30077 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
30079 disable : function(){
30080 if(this.tabPanel.active != this){
30081 this.disabled = true;
30082 this.pnode.addClass("disabled");
30087 * Enables this TabPanelItem if it was previously disabled.
30089 enable : function(){
30090 this.disabled = false;
30091 this.pnode.removeClass("disabled");
30095 * Sets the content for this TabPanelItem.
30096 * @param {String} content The content
30097 * @param {Boolean} loadScripts true to look for and load scripts
30099 setContent : function(content, loadScripts){
30100 this.bodyEl.update(content, loadScripts);
30104 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
30105 * @return {Roo.UpdateManager} The UpdateManager
30107 getUpdateManager : function(){
30108 return this.bodyEl.getUpdateManager();
30112 * Set a URL to be used to load the content for this TabPanelItem.
30113 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
30114 * @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)
30115 * @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)
30116 * @return {Roo.UpdateManager} The UpdateManager
30118 setUrl : function(url, params, loadOnce){
30119 if(this.refreshDelegate){
30120 this.un('activate', this.refreshDelegate);
30122 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
30123 this.on("activate", this.refreshDelegate);
30124 return this.bodyEl.getUpdateManager();
30128 _handleRefresh : function(url, params, loadOnce){
30129 if(!loadOnce || !this.loaded){
30130 var updater = this.bodyEl.getUpdateManager();
30131 updater.update(url, params, this._setLoaded.createDelegate(this));
30136 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
30137 * Will fail silently if the setUrl method has not been called.
30138 * This does not activate the panel, just updates its content.
30140 refresh : function(){
30141 if(this.refreshDelegate){
30142 this.loaded = false;
30143 this.refreshDelegate();
30148 _setLoaded : function(){
30149 this.loaded = true;
30153 closeClick : function(e){
30156 this.fireEvent("beforeclose", this, o);
30157 if(o.cancel !== true){
30158 this.tabPanel.removeTab(this.id);
30162 * The text displayed in the tooltip for the close icon.
30165 closeText : "Close this tab"
30169 Roo.TabPanel.prototype.createStrip = function(container){
30170 var strip = document.createElement("div");
30171 strip.className = "x-tabs-wrap";
30172 container.appendChild(strip);
30176 Roo.TabPanel.prototype.createStripList = function(strip){
30177 // div wrapper for retard IE
30178 // returns the "tr" element.
30179 strip.innerHTML = '<div class="x-tabs-strip-wrap">'+
30180 '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
30181 '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
30182 return strip.firstChild.firstChild.firstChild.firstChild;
30185 Roo.TabPanel.prototype.createBody = function(container){
30186 var body = document.createElement("div");
30187 Roo.id(body, "tab-body");
30188 Roo.fly(body).addClass("x-tabs-body");
30189 container.appendChild(body);
30193 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
30194 var body = Roo.getDom(id);
30196 body = document.createElement("div");
30199 Roo.fly(body).addClass("x-tabs-item-body");
30200 bodyEl.insertBefore(body, bodyEl.firstChild);
30204 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
30205 var td = document.createElement("td");
30206 stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
30207 //stripEl.appendChild(td);
30209 td.className = "x-tabs-closable";
30210 if(!this.closeTpl){
30211 this.closeTpl = new Roo.Template(
30212 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
30213 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
30214 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
30217 var el = this.closeTpl.overwrite(td, {"text": text});
30218 var close = el.getElementsByTagName("div")[0];
30219 var inner = el.getElementsByTagName("em")[0];
30220 return {"el": el, "close": close, "inner": inner};
30223 this.tabTpl = new Roo.Template(
30224 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
30225 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
30228 var el = this.tabTpl.overwrite(td, {"text": text});
30229 var inner = el.getElementsByTagName("em")[0];
30230 return {"el": el, "inner": inner};
30234 * Ext JS Library 1.1.1
30235 * Copyright(c) 2006-2007, Ext JS, LLC.
30237 * Originally Released Under LGPL - original licence link has changed is not relivant.
30240 * <script type="text/javascript">
30244 * @class Roo.Button
30245 * @extends Roo.util.Observable
30246 * Simple Button class
30247 * @cfg {String} text The button text
30248 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
30249 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
30250 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
30251 * @cfg {Object} scope The scope of the handler
30252 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
30253 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
30254 * @cfg {Boolean} hidden True to start hidden (defaults to false)
30255 * @cfg {Boolean} disabled True to start disabled (defaults to false)
30256 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
30257 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
30258 applies if enableToggle = true)
30259 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
30260 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
30261 an {@link Roo.util.ClickRepeater} config object (defaults to false).
30263 * Create a new button
30264 * @param {Object} config The config object
30266 Roo.Button = function(renderTo, config)
30270 renderTo = config.renderTo || false;
30273 Roo.apply(this, config);
30277 * Fires when this button is clicked
30278 * @param {Button} this
30279 * @param {EventObject} e The click event
30284 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
30285 * @param {Button} this
30286 * @param {Boolean} pressed
30291 * Fires when the mouse hovers over the button
30292 * @param {Button} this
30293 * @param {Event} e The event object
30295 'mouseover' : true,
30298 * Fires when the mouse exits the button
30299 * @param {Button} this
30300 * @param {Event} e The event object
30305 * Fires when the button is rendered
30306 * @param {Button} this
30311 this.menu = Roo.menu.MenuMgr.get(this.menu);
30313 // register listeners first!! - so render can be captured..
30314 Roo.util.Observable.call(this);
30316 this.render(renderTo);
30322 Roo.extend(Roo.Button, Roo.util.Observable, {
30328 * Read-only. True if this button is hidden
30333 * Read-only. True if this button is disabled
30338 * Read-only. True if this button is pressed (only if enableToggle = true)
30344 * @cfg {Number} tabIndex
30345 * The DOM tabIndex for this button (defaults to undefined)
30347 tabIndex : undefined,
30350 * @cfg {Boolean} enableToggle
30351 * True to enable pressed/not pressed toggling (defaults to false)
30353 enableToggle: false,
30355 * @cfg {Roo.menu.Menu} menu
30356 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
30360 * @cfg {String} menuAlign
30361 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
30363 menuAlign : "tl-bl?",
30366 * @cfg {String} iconCls
30367 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
30369 iconCls : undefined,
30371 * @cfg {String} type
30372 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
30377 menuClassTarget: 'tr',
30380 * @cfg {String} clickEvent
30381 * The type of event to map to the button's event handler (defaults to 'click')
30383 clickEvent : 'click',
30386 * @cfg {Boolean} handleMouseEvents
30387 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
30389 handleMouseEvents : true,
30392 * @cfg {String} tooltipType
30393 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
30395 tooltipType : 'qtip',
30398 * @cfg {String} cls
30399 * A CSS class to apply to the button's main element.
30403 * @cfg {Roo.Template} template (Optional)
30404 * An {@link Roo.Template} with which to create the Button's main element. This Template must
30405 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
30406 * require code modifications if required elements (e.g. a button) aren't present.
30410 render : function(renderTo){
30412 if(this.hideParent){
30413 this.parentEl = Roo.get(renderTo);
30415 if(!this.dhconfig){
30416 if(!this.template){
30417 if(!Roo.Button.buttonTemplate){
30418 // hideous table template
30419 Roo.Button.buttonTemplate = new Roo.Template(
30420 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
30421 '<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>',
30422 "</tr></tbody></table>");
30424 this.template = Roo.Button.buttonTemplate;
30426 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
30427 var btnEl = btn.child("button:first");
30428 btnEl.on('focus', this.onFocus, this);
30429 btnEl.on('blur', this.onBlur, this);
30431 btn.addClass(this.cls);
30434 btnEl.setStyle('background-image', 'url(' +this.icon +')');
30437 btnEl.addClass(this.iconCls);
30439 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
30442 if(this.tabIndex !== undefined){
30443 btnEl.dom.tabIndex = this.tabIndex;
30446 if(typeof this.tooltip == 'object'){
30447 Roo.QuickTips.tips(Roo.apply({
30451 btnEl.dom[this.tooltipType] = this.tooltip;
30455 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
30459 this.el.dom.id = this.el.id = this.id;
30462 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
30463 this.menu.on("show", this.onMenuShow, this);
30464 this.menu.on("hide", this.onMenuHide, this);
30466 btn.addClass("x-btn");
30467 if(Roo.isIE && !Roo.isIE7){
30468 this.autoWidth.defer(1, this);
30472 if(this.handleMouseEvents){
30473 btn.on("mouseover", this.onMouseOver, this);
30474 btn.on("mouseout", this.onMouseOut, this);
30475 btn.on("mousedown", this.onMouseDown, this);
30477 btn.on(this.clickEvent, this.onClick, this);
30478 //btn.on("mouseup", this.onMouseUp, this);
30485 Roo.ButtonToggleMgr.register(this);
30487 this.el.addClass("x-btn-pressed");
30490 var repeater = new Roo.util.ClickRepeater(btn,
30491 typeof this.repeat == "object" ? this.repeat : {}
30493 repeater.on("click", this.onClick, this);
30496 this.fireEvent('render', this);
30500 * Returns the button's underlying element
30501 * @return {Roo.Element} The element
30503 getEl : function(){
30508 * Destroys this Button and removes any listeners.
30510 destroy : function(){
30511 Roo.ButtonToggleMgr.unregister(this);
30512 this.el.removeAllListeners();
30513 this.purgeListeners();
30518 autoWidth : function(){
30520 this.el.setWidth("auto");
30521 if(Roo.isIE7 && Roo.isStrict){
30522 var ib = this.el.child('button');
30523 if(ib && ib.getWidth() > 20){
30525 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
30530 this.el.beginMeasure();
30532 if(this.el.getWidth() < this.minWidth){
30533 this.el.setWidth(this.minWidth);
30536 this.el.endMeasure();
30543 * Assigns this button's click handler
30544 * @param {Function} handler The function to call when the button is clicked
30545 * @param {Object} scope (optional) Scope for the function passed in
30547 setHandler : function(handler, scope){
30548 this.handler = handler;
30549 this.scope = scope;
30553 * Sets this button's text
30554 * @param {String} text The button text
30556 setText : function(text){
30559 this.el.child("td.x-btn-center button.x-btn-text").update(text);
30565 * Gets the text for this button
30566 * @return {String} The button text
30568 getText : function(){
30576 this.hidden = false;
30578 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
30586 this.hidden = true;
30588 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
30593 * Convenience function for boolean show/hide
30594 * @param {Boolean} visible True to show, false to hide
30596 setVisible: function(visible){
30605 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
30606 * @param {Boolean} state (optional) Force a particular state
30608 toggle : function(state){
30609 state = state === undefined ? !this.pressed : state;
30610 if(state != this.pressed){
30612 this.el.addClass("x-btn-pressed");
30613 this.pressed = true;
30614 this.fireEvent("toggle", this, true);
30616 this.el.removeClass("x-btn-pressed");
30617 this.pressed = false;
30618 this.fireEvent("toggle", this, false);
30620 if(this.toggleHandler){
30621 this.toggleHandler.call(this.scope || this, this, state);
30629 focus : function(){
30630 this.el.child('button:first').focus();
30634 * Disable this button
30636 disable : function(){
30638 this.el.addClass("x-btn-disabled");
30640 this.disabled = true;
30644 * Enable this button
30646 enable : function(){
30648 this.el.removeClass("x-btn-disabled");
30650 this.disabled = false;
30654 * Convenience function for boolean enable/disable
30655 * @param {Boolean} enabled True to enable, false to disable
30657 setDisabled : function(v){
30658 this[v !== true ? "enable" : "disable"]();
30662 onClick : function(e)
30665 e.preventDefault();
30670 if(!this.disabled){
30671 if(this.enableToggle){
30674 if(this.menu && !this.menu.isVisible()){
30675 this.menu.show(this.el, this.menuAlign);
30677 this.fireEvent("click", this, e);
30679 this.el.removeClass("x-btn-over");
30680 this.handler.call(this.scope || this, this, e);
30685 onMouseOver : function(e){
30686 if(!this.disabled){
30687 this.el.addClass("x-btn-over");
30688 this.fireEvent('mouseover', this, e);
30692 onMouseOut : function(e){
30693 if(!e.within(this.el, true)){
30694 this.el.removeClass("x-btn-over");
30695 this.fireEvent('mouseout', this, e);
30699 onFocus : function(e){
30700 if(!this.disabled){
30701 this.el.addClass("x-btn-focus");
30705 onBlur : function(e){
30706 this.el.removeClass("x-btn-focus");
30709 onMouseDown : function(e){
30710 if(!this.disabled && e.button == 0){
30711 this.el.addClass("x-btn-click");
30712 Roo.get(document).on('mouseup', this.onMouseUp, this);
30716 onMouseUp : function(e){
30718 this.el.removeClass("x-btn-click");
30719 Roo.get(document).un('mouseup', this.onMouseUp, this);
30723 onMenuShow : function(e){
30724 this.el.addClass("x-btn-menu-active");
30727 onMenuHide : function(e){
30728 this.el.removeClass("x-btn-menu-active");
30732 // Private utility class used by Button
30733 Roo.ButtonToggleMgr = function(){
30736 function toggleGroup(btn, state){
30738 var g = groups[btn.toggleGroup];
30739 for(var i = 0, l = g.length; i < l; i++){
30741 g[i].toggle(false);
30748 register : function(btn){
30749 if(!btn.toggleGroup){
30752 var g = groups[btn.toggleGroup];
30754 g = groups[btn.toggleGroup] = [];
30757 btn.on("toggle", toggleGroup);
30760 unregister : function(btn){
30761 if(!btn.toggleGroup){
30764 var g = groups[btn.toggleGroup];
30767 btn.un("toggle", toggleGroup);
30773 * Ext JS Library 1.1.1
30774 * Copyright(c) 2006-2007, Ext JS, LLC.
30776 * Originally Released Under LGPL - original licence link has changed is not relivant.
30779 * <script type="text/javascript">
30783 * @class Roo.SplitButton
30784 * @extends Roo.Button
30785 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
30786 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
30787 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
30788 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
30789 * @cfg {String} arrowTooltip The title attribute of the arrow
30791 * Create a new menu button
30792 * @param {String/HTMLElement/Element} renderTo The element to append the button to
30793 * @param {Object} config The config object
30795 Roo.SplitButton = function(renderTo, config){
30796 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
30798 * @event arrowclick
30799 * Fires when this button's arrow is clicked
30800 * @param {SplitButton} this
30801 * @param {EventObject} e The click event
30803 this.addEvents({"arrowclick":true});
30806 Roo.extend(Roo.SplitButton, Roo.Button, {
30807 render : function(renderTo){
30808 // this is one sweet looking template!
30809 var tpl = new Roo.Template(
30810 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
30811 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
30812 '<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>',
30813 "</tbody></table></td><td>",
30814 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
30815 '<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>',
30816 "</tbody></table></td></tr></table>"
30818 var btn = tpl.append(renderTo, [this.text, this.type], true);
30819 var btnEl = btn.child("button");
30821 btn.addClass(this.cls);
30824 btnEl.setStyle('background-image', 'url(' +this.icon +')');
30827 btnEl.addClass(this.iconCls);
30829 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
30833 if(this.handleMouseEvents){
30834 btn.on("mouseover", this.onMouseOver, this);
30835 btn.on("mouseout", this.onMouseOut, this);
30836 btn.on("mousedown", this.onMouseDown, this);
30837 btn.on("mouseup", this.onMouseUp, this);
30839 btn.on(this.clickEvent, this.onClick, this);
30841 if(typeof this.tooltip == 'object'){
30842 Roo.QuickTips.tips(Roo.apply({
30846 btnEl.dom[this.tooltipType] = this.tooltip;
30849 if(this.arrowTooltip){
30850 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
30859 this.el.addClass("x-btn-pressed");
30861 if(Roo.isIE && !Roo.isIE7){
30862 this.autoWidth.defer(1, this);
30867 this.menu.on("show", this.onMenuShow, this);
30868 this.menu.on("hide", this.onMenuHide, this);
30870 this.fireEvent('render', this);
30874 autoWidth : function(){
30876 var tbl = this.el.child("table:first");
30877 var tbl2 = this.el.child("table:last");
30878 this.el.setWidth("auto");
30879 tbl.setWidth("auto");
30880 if(Roo.isIE7 && Roo.isStrict){
30881 var ib = this.el.child('button:first');
30882 if(ib && ib.getWidth() > 20){
30884 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
30889 this.el.beginMeasure();
30891 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
30892 tbl.setWidth(this.minWidth-tbl2.getWidth());
30895 this.el.endMeasure();
30898 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
30902 * Sets this button's click handler
30903 * @param {Function} handler The function to call when the button is clicked
30904 * @param {Object} scope (optional) Scope for the function passed above
30906 setHandler : function(handler, scope){
30907 this.handler = handler;
30908 this.scope = scope;
30912 * Sets this button's arrow click handler
30913 * @param {Function} handler The function to call when the arrow is clicked
30914 * @param {Object} scope (optional) Scope for the function passed above
30916 setArrowHandler : function(handler, scope){
30917 this.arrowHandler = handler;
30918 this.scope = scope;
30924 focus : function(){
30926 this.el.child("button:first").focus();
30931 onClick : function(e){
30932 e.preventDefault();
30933 if(!this.disabled){
30934 if(e.getTarget(".x-btn-menu-arrow-wrap")){
30935 if(this.menu && !this.menu.isVisible()){
30936 this.menu.show(this.el, this.menuAlign);
30938 this.fireEvent("arrowclick", this, e);
30939 if(this.arrowHandler){
30940 this.arrowHandler.call(this.scope || this, this, e);
30943 this.fireEvent("click", this, e);
30945 this.handler.call(this.scope || this, this, e);
30951 onMouseDown : function(e){
30952 if(!this.disabled){
30953 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
30957 onMouseUp : function(e){
30958 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
30963 // backwards compat
30964 Roo.MenuButton = Roo.SplitButton;/*
30966 * Ext JS Library 1.1.1
30967 * Copyright(c) 2006-2007, Ext JS, LLC.
30969 * Originally Released Under LGPL - original licence link has changed is not relivant.
30972 * <script type="text/javascript">
30976 * @class Roo.Toolbar
30977 * @children Roo.Toolbar.Item Roo.form.Field
30978 * Basic Toolbar class.
30980 * Creates a new Toolbar
30981 * @param {Object} container The config object
30983 Roo.Toolbar = function(container, buttons, config)
30985 /// old consturctor format still supported..
30986 if(container instanceof Array){ // omit the container for later rendering
30987 buttons = container;
30991 if (typeof(container) == 'object' && container.xtype) {
30992 config = container;
30993 container = config.container;
30994 buttons = config.buttons || []; // not really - use items!!
30997 if (config && config.items) {
30998 xitems = config.items;
30999 delete config.items;
31001 Roo.apply(this, config);
31002 this.buttons = buttons;
31005 this.render(container);
31007 this.xitems = xitems;
31008 Roo.each(xitems, function(b) {
31014 Roo.Toolbar.prototype = {
31016 * @cfg {Array} items
31017 * array of button configs or elements to add (will be converted to a MixedCollection)
31021 * @cfg {String/HTMLElement/Element} container
31022 * The id or element that will contain the toolbar
31025 render : function(ct){
31026 this.el = Roo.get(ct);
31028 this.el.addClass(this.cls);
31030 // using a table allows for vertical alignment
31031 // 100% width is needed by Safari...
31032 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
31033 this.tr = this.el.child("tr", true);
31035 this.items = new Roo.util.MixedCollection(false, function(o){
31036 return o.id || ("item" + (++autoId));
31039 this.add.apply(this, this.buttons);
31040 delete this.buttons;
31045 * Adds element(s) to the toolbar -- this function takes a variable number of
31046 * arguments of mixed type and adds them to the toolbar.
31047 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
31049 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
31050 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
31051 * <li>Field: Any form field (equivalent to {@link #addField})</li>
31052 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
31053 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
31054 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
31055 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
31056 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
31057 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
31059 * @param {Mixed} arg2
31060 * @param {Mixed} etc.
31063 var a = arguments, l = a.length;
31064 for(var i = 0; i < l; i++){
31069 _add : function(el) {
31072 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
31075 if (el.applyTo){ // some kind of form field
31076 return this.addField(el);
31078 if (el.render){ // some kind of Toolbar.Item
31079 return this.addItem(el);
31081 if (typeof el == "string"){ // string
31082 if(el == "separator" || el == "-"){
31083 return this.addSeparator();
31086 return this.addSpacer();
31089 return this.addFill();
31091 return this.addText(el);
31094 if(el.tagName){ // element
31095 return this.addElement(el);
31097 if(typeof el == "object"){ // must be button config?
31098 return this.addButton(el);
31100 // and now what?!?!
31106 * Add an Xtype element
31107 * @param {Object} xtype Xtype Object
31108 * @return {Object} created Object
31110 addxtype : function(e){
31111 return this.add(e);
31115 * Returns the Element for this toolbar.
31116 * @return {Roo.Element}
31118 getEl : function(){
31124 * @return {Roo.Toolbar.Item} The separator item
31126 addSeparator : function(){
31127 return this.addItem(new Roo.Toolbar.Separator());
31131 * Adds a spacer element
31132 * @return {Roo.Toolbar.Spacer} The spacer item
31134 addSpacer : function(){
31135 return this.addItem(new Roo.Toolbar.Spacer());
31139 * Adds a fill element that forces subsequent additions to the right side of the toolbar
31140 * @return {Roo.Toolbar.Fill} The fill item
31142 addFill : function(){
31143 return this.addItem(new Roo.Toolbar.Fill());
31147 * Adds any standard HTML element to the toolbar
31148 * @param {String/HTMLElement/Element} el The element or id of the element to add
31149 * @return {Roo.Toolbar.Item} The element's item
31151 addElement : function(el){
31152 return this.addItem(new Roo.Toolbar.Item(el));
31155 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
31156 * @type Roo.util.MixedCollection
31161 * Adds any Toolbar.Item or subclass
31162 * @param {Roo.Toolbar.Item} item
31163 * @return {Roo.Toolbar.Item} The item
31165 addItem : function(item){
31166 var td = this.nextBlock();
31168 this.items.add(item);
31173 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
31174 * @param {Object/Array} config A button config or array of configs
31175 * @return {Roo.Toolbar.Button/Array}
31177 addButton : function(config){
31178 if(config instanceof Array){
31180 for(var i = 0, len = config.length; i < len; i++) {
31181 buttons.push(this.addButton(config[i]));
31186 if(!(config instanceof Roo.Toolbar.Button)){
31188 new Roo.Toolbar.SplitButton(config) :
31189 new Roo.Toolbar.Button(config);
31191 var td = this.nextBlock();
31198 * Adds text to the toolbar
31199 * @param {String} text The text to add
31200 * @return {Roo.Toolbar.Item} The element's item
31202 addText : function(text){
31203 return this.addItem(new Roo.Toolbar.TextItem(text));
31207 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
31208 * @param {Number} index The index where the item is to be inserted
31209 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
31210 * @return {Roo.Toolbar.Button/Item}
31212 insertButton : function(index, item){
31213 if(item instanceof Array){
31215 for(var i = 0, len = item.length; i < len; i++) {
31216 buttons.push(this.insertButton(index + i, item[i]));
31220 if (!(item instanceof Roo.Toolbar.Button)){
31221 item = new Roo.Toolbar.Button(item);
31223 var td = document.createElement("td");
31224 this.tr.insertBefore(td, this.tr.childNodes[index]);
31226 this.items.insert(index, item);
31231 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
31232 * @param {Object} config
31233 * @return {Roo.Toolbar.Item} The element's item
31235 addDom : function(config, returnEl){
31236 var td = this.nextBlock();
31237 Roo.DomHelper.overwrite(td, config);
31238 var ti = new Roo.Toolbar.Item(td.firstChild);
31240 this.items.add(ti);
31245 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
31246 * @type Roo.util.MixedCollection
31251 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc).
31252 * Note: the field should not have been rendered yet. For a field that has already been
31253 * rendered, use {@link #addElement}.
31254 * @param {Roo.form.Field} field
31255 * @return {Roo.ToolbarItem}
31259 addField : function(field) {
31260 if (!this.fields) {
31262 this.fields = new Roo.util.MixedCollection(false, function(o){
31263 return o.id || ("item" + (++autoId));
31268 var td = this.nextBlock();
31270 var ti = new Roo.Toolbar.Item(td.firstChild);
31272 this.items.add(ti);
31273 this.fields.add(field);
31284 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
31285 this.el.child('div').hide();
31293 this.el.child('div').show();
31297 nextBlock : function(){
31298 var td = document.createElement("td");
31299 this.tr.appendChild(td);
31304 destroy : function(){
31305 if(this.items){ // rendered?
31306 Roo.destroy.apply(Roo, this.items.items);
31308 if(this.fields){ // rendered?
31309 Roo.destroy.apply(Roo, this.fields.items);
31311 Roo.Element.uncache(this.el, this.tr);
31316 * @class Roo.Toolbar.Item
31317 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
31319 * Creates a new Item
31320 * @param {HTMLElement} el
31322 Roo.Toolbar.Item = function(el){
31324 if (typeof (el.xtype) != 'undefined') {
31329 this.el = Roo.getDom(el);
31330 this.id = Roo.id(this.el);
31331 this.hidden = false;
31336 * Fires when the button is rendered
31337 * @param {Button} this
31341 Roo.Toolbar.Item.superclass.constructor.call(this,cfg);
31343 Roo.extend(Roo.Toolbar.Item, Roo.util.Observable, {
31344 //Roo.Toolbar.Item.prototype = {
31347 * Get this item's HTML Element
31348 * @return {HTMLElement}
31350 getEl : function(){
31355 render : function(td){
31358 td.appendChild(this.el);
31360 this.fireEvent('render', this);
31364 * Removes and destroys this item.
31366 destroy : function(){
31367 this.td.parentNode.removeChild(this.td);
31374 this.hidden = false;
31375 this.td.style.display = "";
31382 this.hidden = true;
31383 this.td.style.display = "none";
31387 * Convenience function for boolean show/hide.
31388 * @param {Boolean} visible true to show/false to hide
31390 setVisible: function(visible){
31399 * Try to focus this item.
31401 focus : function(){
31402 Roo.fly(this.el).focus();
31406 * Disables this item.
31408 disable : function(){
31409 Roo.fly(this.td).addClass("x-item-disabled");
31410 this.disabled = true;
31411 this.el.disabled = true;
31415 * Enables this item.
31417 enable : function(){
31418 Roo.fly(this.td).removeClass("x-item-disabled");
31419 this.disabled = false;
31420 this.el.disabled = false;
31426 * @class Roo.Toolbar.Separator
31427 * @extends Roo.Toolbar.Item
31428 * A simple toolbar separator class
31430 * Creates a new Separator
31432 Roo.Toolbar.Separator = function(cfg){
31434 var s = document.createElement("span");
31435 s.className = "ytb-sep";
31440 Roo.Toolbar.Separator.superclass.constructor.call(this, cfg || s);
31442 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
31443 enable:Roo.emptyFn,
31444 disable:Roo.emptyFn,
31449 * @class Roo.Toolbar.Spacer
31450 * @extends Roo.Toolbar.Item
31451 * A simple element that adds extra horizontal space to a toolbar.
31453 * Creates a new Spacer
31455 Roo.Toolbar.Spacer = function(cfg){
31456 var s = document.createElement("div");
31457 s.className = "ytb-spacer";
31461 Roo.Toolbar.Spacer.superclass.constructor.call(this, cfg || s);
31463 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
31464 enable:Roo.emptyFn,
31465 disable:Roo.emptyFn,
31470 * @class Roo.Toolbar.Fill
31471 * @extends Roo.Toolbar.Spacer
31472 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
31474 * Creates a new Spacer
31476 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
31478 render : function(td){
31479 td.style.width = '100%';
31480 Roo.Toolbar.Fill.superclass.render.call(this, td);
31485 * @class Roo.Toolbar.TextItem
31486 * @extends Roo.Toolbar.Item
31487 * A simple class that renders text directly into a toolbar.
31489 * Creates a new TextItem
31490 * @cfg {string} text
31492 Roo.Toolbar.TextItem = function(cfg){
31493 var text = cfg || "";
31494 if (typeof(cfg) == 'object') {
31495 text = cfg.text || "";
31499 var s = document.createElement("span");
31500 s.className = "ytb-text";
31501 s.innerHTML = text;
31506 Roo.Toolbar.TextItem.superclass.constructor.call(this, cfg || s);
31508 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
31511 enable:Roo.emptyFn,
31512 disable:Roo.emptyFn,
31517 * @class Roo.Toolbar.Button
31518 * @extends Roo.Button
31519 * A button that renders into a toolbar.
31521 * Creates a new Button
31522 * @param {Object} config A standard {@link Roo.Button} config object
31524 Roo.Toolbar.Button = function(config){
31525 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
31527 Roo.extend(Roo.Toolbar.Button, Roo.Button,
31531 render : function(td){
31533 Roo.Toolbar.Button.superclass.render.call(this, td);
31537 * Removes and destroys this button
31539 destroy : function(){
31540 Roo.Toolbar.Button.superclass.destroy.call(this);
31541 this.td.parentNode.removeChild(this.td);
31545 * Shows this button
31548 this.hidden = false;
31549 this.td.style.display = "";
31553 * Hides this button
31556 this.hidden = true;
31557 this.td.style.display = "none";
31561 * Disables this item
31563 disable : function(){
31564 Roo.fly(this.td).addClass("x-item-disabled");
31565 this.disabled = true;
31569 * Enables this item
31571 enable : function(){
31572 Roo.fly(this.td).removeClass("x-item-disabled");
31573 this.disabled = false;
31576 // backwards compat
31577 Roo.ToolbarButton = Roo.Toolbar.Button;
31580 * @class Roo.Toolbar.SplitButton
31581 * @extends Roo.SplitButton
31582 * A menu button that renders into a toolbar.
31584 * Creates a new SplitButton
31585 * @param {Object} config A standard {@link Roo.SplitButton} config object
31587 Roo.Toolbar.SplitButton = function(config){
31588 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
31590 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
31591 render : function(td){
31593 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
31597 * Removes and destroys this button
31599 destroy : function(){
31600 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
31601 this.td.parentNode.removeChild(this.td);
31605 * Shows this button
31608 this.hidden = false;
31609 this.td.style.display = "";
31613 * Hides this button
31616 this.hidden = true;
31617 this.td.style.display = "none";
31621 // backwards compat
31622 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
31624 * Ext JS Library 1.1.1
31625 * Copyright(c) 2006-2007, Ext JS, LLC.
31627 * Originally Released Under LGPL - original licence link has changed is not relivant.
31630 * <script type="text/javascript">
31634 * @class Roo.PagingToolbar
31635 * @extends Roo.Toolbar
31636 * @children Roo.Toolbar.Item Roo.form.Field
31637 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
31639 * Create a new PagingToolbar
31640 * @param {Object} config The config object
31642 Roo.PagingToolbar = function(el, ds, config)
31644 // old args format still supported... - xtype is prefered..
31645 if (typeof(el) == 'object' && el.xtype) {
31646 // created from xtype...
31648 ds = el.dataSource;
31649 el = config.container;
31652 if (config.items) {
31653 items = config.items;
31657 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
31660 this.renderButtons(this.el);
31663 // supprot items array.
31665 Roo.each(items, function(e) {
31666 this.add(Roo.factory(e));
31671 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
31674 * @cfg {String/HTMLElement/Element} container
31675 * container The id or element that will contain the toolbar
31678 * @cfg {Boolean} displayInfo
31679 * True to display the displayMsg (defaults to false)
31684 * @cfg {Number} pageSize
31685 * The number of records to display per page (defaults to 20)
31689 * @cfg {String} displayMsg
31690 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
31692 displayMsg : 'Displaying {0} - {1} of {2}',
31694 * @cfg {String} emptyMsg
31695 * The message to display when no records are found (defaults to "No data to display")
31697 emptyMsg : 'No data to display',
31699 * Customizable piece of the default paging text (defaults to "Page")
31702 beforePageText : "Page",
31704 * Customizable piece of the default paging text (defaults to "of %0")
31707 afterPageText : "of {0}",
31709 * Customizable piece of the default paging text (defaults to "First Page")
31712 firstText : "First Page",
31714 * Customizable piece of the default paging text (defaults to "Previous Page")
31717 prevText : "Previous Page",
31719 * Customizable piece of the default paging text (defaults to "Next Page")
31722 nextText : "Next Page",
31724 * Customizable piece of the default paging text (defaults to "Last Page")
31727 lastText : "Last Page",
31729 * Customizable piece of the default paging text (defaults to "Refresh")
31732 refreshText : "Refresh",
31735 renderButtons : function(el){
31736 Roo.PagingToolbar.superclass.render.call(this, el);
31737 this.first = this.addButton({
31738 tooltip: this.firstText,
31739 cls: "x-btn-icon x-grid-page-first",
31741 handler: this.onClick.createDelegate(this, ["first"])
31743 this.prev = this.addButton({
31744 tooltip: this.prevText,
31745 cls: "x-btn-icon x-grid-page-prev",
31747 handler: this.onClick.createDelegate(this, ["prev"])
31749 //this.addSeparator();
31750 this.add(this.beforePageText);
31751 this.field = Roo.get(this.addDom({
31756 cls: "x-grid-page-number"
31758 this.field.on("keydown", this.onPagingKeydown, this);
31759 this.field.on("focus", function(){this.dom.select();});
31760 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
31761 this.field.setHeight(18);
31762 //this.addSeparator();
31763 this.next = this.addButton({
31764 tooltip: this.nextText,
31765 cls: "x-btn-icon x-grid-page-next",
31767 handler: this.onClick.createDelegate(this, ["next"])
31769 this.last = this.addButton({
31770 tooltip: this.lastText,
31771 cls: "x-btn-icon x-grid-page-last",
31773 handler: this.onClick.createDelegate(this, ["last"])
31775 //this.addSeparator();
31776 this.loading = this.addButton({
31777 tooltip: this.refreshText,
31778 cls: "x-btn-icon x-grid-loading",
31779 handler: this.onClick.createDelegate(this, ["refresh"])
31782 if(this.displayInfo){
31783 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
31788 updateInfo : function(){
31789 if(this.displayEl){
31790 var count = this.ds.getCount();
31791 var msg = count == 0 ?
31795 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
31797 this.displayEl.update(msg);
31802 onLoad : function(ds, r, o){
31803 this.cursor = o.params ? o.params.start : 0;
31804 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
31806 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
31807 this.field.dom.value = ap;
31808 this.first.setDisabled(ap == 1);
31809 this.prev.setDisabled(ap == 1);
31810 this.next.setDisabled(ap == ps);
31811 this.last.setDisabled(ap == ps);
31812 this.loading.enable();
31817 getPageData : function(){
31818 var total = this.ds.getTotalCount();
31821 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
31822 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
31827 onLoadError : function(){
31828 this.loading.enable();
31832 onPagingKeydown : function(e){
31833 var k = e.getKey();
31834 var d = this.getPageData();
31836 var v = this.field.dom.value, pageNum;
31837 if(!v || isNaN(pageNum = parseInt(v, 10))){
31838 this.field.dom.value = d.activePage;
31841 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
31842 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
31845 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))
31847 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
31848 this.field.dom.value = pageNum;
31849 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
31852 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
31854 var v = this.field.dom.value, pageNum;
31855 var increment = (e.shiftKey) ? 10 : 1;
31856 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
31859 if(!v || isNaN(pageNum = parseInt(v, 10))) {
31860 this.field.dom.value = d.activePage;
31863 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
31865 this.field.dom.value = parseInt(v, 10) + increment;
31866 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
31867 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
31874 beforeLoad : function(){
31876 this.loading.disable();
31881 onClick : function(which){
31885 ds.load({params:{start: 0, limit: this.pageSize}});
31888 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
31891 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
31894 var total = ds.getTotalCount();
31895 var extra = total % this.pageSize;
31896 var lastStart = extra ? (total - extra) : total-this.pageSize;
31897 ds.load({params:{start: lastStart, limit: this.pageSize}});
31900 ds.load({params:{start: this.cursor, limit: this.pageSize}});
31906 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
31907 * @param {Roo.data.Store} store The data store to unbind
31909 unbind : function(ds){
31910 ds.un("beforeload", this.beforeLoad, this);
31911 ds.un("load", this.onLoad, this);
31912 ds.un("loadexception", this.onLoadError, this);
31913 ds.un("remove", this.updateInfo, this);
31914 ds.un("add", this.updateInfo, this);
31915 this.ds = undefined;
31919 * Binds the paging toolbar to the specified {@link Roo.data.Store}
31920 * @param {Roo.data.Store} store The data store to bind
31922 bind : function(ds){
31923 ds.on("beforeload", this.beforeLoad, this);
31924 ds.on("load", this.onLoad, this);
31925 ds.on("loadexception", this.onLoadError, this);
31926 ds.on("remove", this.updateInfo, this);
31927 ds.on("add", this.updateInfo, this);
31932 * Ext JS Library 1.1.1
31933 * Copyright(c) 2006-2007, Ext JS, LLC.
31935 * Originally Released Under LGPL - original licence link has changed is not relivant.
31938 * <script type="text/javascript">
31942 * @class Roo.Resizable
31943 * @extends Roo.util.Observable
31944 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
31945 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
31946 * 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
31947 * the element will be wrapped for you automatically.</p>
31948 * <p>Here is the list of valid resize handles:</p>
31951 ------ -------------------
31960 'hd' horizontal drag
31963 * <p>Here's an example showing the creation of a typical Resizable:</p>
31965 var resizer = new Roo.Resizable("element-id", {
31973 resizer.on("resize", myHandler);
31975 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
31976 * resizer.east.setDisplayed(false);</p>
31977 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
31978 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
31979 * resize operation's new size (defaults to [0, 0])
31980 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
31981 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
31982 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
31983 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
31984 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
31985 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
31986 * @cfg {Number} width The width of the element in pixels (defaults to null)
31987 * @cfg {Number} height The height of the element in pixels (defaults to null)
31988 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
31989 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
31990 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
31991 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
31992 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
31993 * in favor of the handles config option (defaults to false)
31994 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
31995 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
31996 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
31997 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
31998 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
31999 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
32000 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
32001 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
32002 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
32003 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
32004 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
32006 * Create a new resizable component
32007 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
32008 * @param {Object} config configuration options
32010 Roo.Resizable = function(el, config)
32012 this.el = Roo.get(el);
32014 if(config && config.wrap){
32015 config.resizeChild = this.el;
32016 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
32017 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
32018 this.el.setStyle("overflow", "hidden");
32019 this.el.setPositioning(config.resizeChild.getPositioning());
32020 config.resizeChild.clearPositioning();
32021 if(!config.width || !config.height){
32022 var csize = config.resizeChild.getSize();
32023 this.el.setSize(csize.width, csize.height);
32025 if(config.pinned && !config.adjustments){
32026 config.adjustments = "auto";
32030 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
32031 this.proxy.unselectable();
32032 this.proxy.enableDisplayMode('block');
32034 Roo.apply(this, config);
32037 this.disableTrackOver = true;
32038 this.el.addClass("x-resizable-pinned");
32040 // if the element isn't positioned, make it relative
32041 var position = this.el.getStyle("position");
32042 if(position != "absolute" && position != "fixed"){
32043 this.el.setStyle("position", "relative");
32045 if(!this.handles){ // no handles passed, must be legacy style
32046 this.handles = 's,e,se';
32047 if(this.multiDirectional){
32048 this.handles += ',n,w';
32051 if(this.handles == "all"){
32052 this.handles = "n s e w ne nw se sw";
32054 var hs = this.handles.split(/\s*?[,;]\s*?| /);
32055 var ps = Roo.Resizable.positions;
32056 for(var i = 0, len = hs.length; i < len; i++){
32057 if(hs[i] && ps[hs[i]]){
32058 var pos = ps[hs[i]];
32059 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
32063 this.corner = this.southeast;
32065 // updateBox = the box can move..
32066 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
32067 this.updateBox = true;
32070 this.activeHandle = null;
32072 if(this.resizeChild){
32073 if(typeof this.resizeChild == "boolean"){
32074 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
32076 this.resizeChild = Roo.get(this.resizeChild, true);
32080 if(this.adjustments == "auto"){
32081 var rc = this.resizeChild;
32082 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
32083 if(rc && (hw || hn)){
32084 rc.position("relative");
32085 rc.setLeft(hw ? hw.el.getWidth() : 0);
32086 rc.setTop(hn ? hn.el.getHeight() : 0);
32088 this.adjustments = [
32089 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
32090 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
32094 if(this.draggable){
32095 this.dd = this.dynamic ?
32096 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
32097 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
32103 * @event beforeresize
32104 * Fired before resize is allowed. Set enabled to false to cancel resize.
32105 * @param {Roo.Resizable} this
32106 * @param {Roo.EventObject} e The mousedown event
32108 "beforeresize" : true,
32111 * Fired a resizing.
32112 * @param {Roo.Resizable} this
32113 * @param {Number} x The new x position
32114 * @param {Number} y The new y position
32115 * @param {Number} w The new w width
32116 * @param {Number} h The new h hight
32117 * @param {Roo.EventObject} e The mouseup event
32122 * Fired after a resize.
32123 * @param {Roo.Resizable} this
32124 * @param {Number} width The new width
32125 * @param {Number} height The new height
32126 * @param {Roo.EventObject} e The mouseup event
32131 if(this.width !== null && this.height !== null){
32132 this.resizeTo(this.width, this.height);
32134 this.updateChildSize();
32137 this.el.dom.style.zoom = 1;
32139 Roo.Resizable.superclass.constructor.call(this);
32142 Roo.extend(Roo.Resizable, Roo.util.Observable, {
32143 resizeChild : false,
32144 adjustments : [0, 0],
32154 multiDirectional : false,
32155 disableTrackOver : false,
32156 easing : 'easeOutStrong',
32157 widthIncrement : 0,
32158 heightIncrement : 0,
32162 preserveRatio : false,
32163 transparent: false,
32169 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
32171 constrainTo: undefined,
32173 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
32175 resizeRegion: undefined,
32179 * Perform a manual resize
32180 * @param {Number} width
32181 * @param {Number} height
32183 resizeTo : function(width, height){
32184 this.el.setSize(width, height);
32185 this.updateChildSize();
32186 this.fireEvent("resize", this, width, height, null);
32190 startSizing : function(e, handle){
32191 this.fireEvent("beforeresize", this, e);
32192 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
32195 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
32196 this.overlay.unselectable();
32197 this.overlay.enableDisplayMode("block");
32198 this.overlay.on("mousemove", this.onMouseMove, this);
32199 this.overlay.on("mouseup", this.onMouseUp, this);
32201 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
32203 this.resizing = true;
32204 this.startBox = this.el.getBox();
32205 this.startPoint = e.getXY();
32206 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
32207 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
32209 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
32210 this.overlay.show();
32212 if(this.constrainTo) {
32213 var ct = Roo.get(this.constrainTo);
32214 this.resizeRegion = ct.getRegion().adjust(
32215 ct.getFrameWidth('t'),
32216 ct.getFrameWidth('l'),
32217 -ct.getFrameWidth('b'),
32218 -ct.getFrameWidth('r')
32222 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
32224 this.proxy.setBox(this.startBox);
32226 this.proxy.setStyle('visibility', 'visible');
32232 onMouseDown : function(handle, e){
32235 this.activeHandle = handle;
32236 this.startSizing(e, handle);
32241 onMouseUp : function(e){
32242 var size = this.resizeElement();
32243 this.resizing = false;
32245 this.overlay.hide();
32247 this.fireEvent("resize", this, size.width, size.height, e);
32251 updateChildSize : function(){
32253 if(this.resizeChild){
32255 var child = this.resizeChild;
32256 var adj = this.adjustments;
32257 if(el.dom.offsetWidth){
32258 var b = el.getSize(true);
32259 child.setSize(b.width+adj[0], b.height+adj[1]);
32261 // Second call here for IE
32262 // The first call enables instant resizing and
32263 // the second call corrects scroll bars if they
32266 setTimeout(function(){
32267 if(el.dom.offsetWidth){
32268 var b = el.getSize(true);
32269 child.setSize(b.width+adj[0], b.height+adj[1]);
32277 snap : function(value, inc, min){
32278 if(!inc || !value) {
32281 var newValue = value;
32282 var m = value % inc;
32285 newValue = value + (inc-m);
32287 newValue = value - m;
32290 return Math.max(min, newValue);
32294 resizeElement : function(){
32295 var box = this.proxy.getBox();
32296 if(this.updateBox){
32297 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
32299 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
32301 this.updateChildSize();
32309 constrain : function(v, diff, m, mx){
32312 }else if(v - diff > mx){
32319 onMouseMove : function(e){
32322 try{// try catch so if something goes wrong the user doesn't get hung
32324 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
32328 //var curXY = this.startPoint;
32329 var curSize = this.curSize || this.startBox;
32330 var x = this.startBox.x, y = this.startBox.y;
32331 var ox = x, oy = y;
32332 var w = curSize.width, h = curSize.height;
32333 var ow = w, oh = h;
32334 var mw = this.minWidth, mh = this.minHeight;
32335 var mxw = this.maxWidth, mxh = this.maxHeight;
32336 var wi = this.widthIncrement;
32337 var hi = this.heightIncrement;
32339 var eventXY = e.getXY();
32340 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
32341 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
32343 var pos = this.activeHandle.position;
32348 w = Math.min(Math.max(mw, w), mxw);
32353 h = Math.min(Math.max(mh, h), mxh);
32358 w = Math.min(Math.max(mw, w), mxw);
32359 h = Math.min(Math.max(mh, h), mxh);
32362 diffY = this.constrain(h, diffY, mh, mxh);
32369 var adiffX = Math.abs(diffX);
32370 var sub = (adiffX % wi); // how much
32371 if (sub > (wi/2)) { // far enough to snap
32372 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
32374 // remove difference..
32375 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
32379 x = Math.max(this.minX, x);
32382 diffX = this.constrain(w, diffX, mw, mxw);
32388 w = Math.min(Math.max(mw, w), mxw);
32389 diffY = this.constrain(h, diffY, mh, mxh);
32394 diffX = this.constrain(w, diffX, mw, mxw);
32395 diffY = this.constrain(h, diffY, mh, mxh);
32402 diffX = this.constrain(w, diffX, mw, mxw);
32404 h = Math.min(Math.max(mh, h), mxh);
32410 var sw = this.snap(w, wi, mw);
32411 var sh = this.snap(h, hi, mh);
32412 if(sw != w || sh != h){
32435 if(this.preserveRatio){
32440 h = Math.min(Math.max(mh, h), mxh);
32445 w = Math.min(Math.max(mw, w), mxw);
32450 w = Math.min(Math.max(mw, w), mxw);
32456 w = Math.min(Math.max(mw, w), mxw);
32462 h = Math.min(Math.max(mh, h), mxh);
32470 h = Math.min(Math.max(mh, h), mxh);
32480 h = Math.min(Math.max(mh, h), mxh);
32488 if (pos == 'hdrag') {
32491 this.proxy.setBounds(x, y, w, h);
32493 this.resizeElement();
32497 this.fireEvent("resizing", this, x, y, w, h, e);
32501 handleOver : function(){
32503 this.el.addClass("x-resizable-over");
32508 handleOut : function(){
32509 if(!this.resizing){
32510 this.el.removeClass("x-resizable-over");
32515 * Returns the element this component is bound to.
32516 * @return {Roo.Element}
32518 getEl : function(){
32523 * Returns the resizeChild element (or null).
32524 * @return {Roo.Element}
32526 getResizeChild : function(){
32527 return this.resizeChild;
32529 groupHandler : function()
32534 * Destroys this resizable. If the element was wrapped and
32535 * removeEl is not true then the element remains.
32536 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
32538 destroy : function(removeEl){
32539 this.proxy.remove();
32541 this.overlay.removeAllListeners();
32542 this.overlay.remove();
32544 var ps = Roo.Resizable.positions;
32546 if(typeof ps[k] != "function" && this[ps[k]]){
32547 var h = this[ps[k]];
32548 h.el.removeAllListeners();
32553 this.el.update("");
32560 // hash to map config positions to true positions
32561 Roo.Resizable.positions = {
32562 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
32567 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
32569 // only initialize the template if resizable is used
32570 var tpl = Roo.DomHelper.createTemplate(
32571 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
32574 Roo.Resizable.Handle.prototype.tpl = tpl;
32576 this.position = pos;
32578 // show north drag fro topdra
32579 var handlepos = pos == 'hdrag' ? 'north' : pos;
32581 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
32582 if (pos == 'hdrag') {
32583 this.el.setStyle('cursor', 'pointer');
32585 this.el.unselectable();
32587 this.el.setOpacity(0);
32589 this.el.on("mousedown", this.onMouseDown, this);
32590 if(!disableTrackOver){
32591 this.el.on("mouseover", this.onMouseOver, this);
32592 this.el.on("mouseout", this.onMouseOut, this);
32597 Roo.Resizable.Handle.prototype = {
32598 afterResize : function(rz){
32603 onMouseDown : function(e){
32604 this.rz.onMouseDown(this, e);
32607 onMouseOver : function(e){
32608 this.rz.handleOver(this, e);
32611 onMouseOut : function(e){
32612 this.rz.handleOut(this, e);
32616 * Ext JS Library 1.1.1
32617 * Copyright(c) 2006-2007, Ext JS, LLC.
32619 * Originally Released Under LGPL - original licence link has changed is not relivant.
32622 * <script type="text/javascript">
32626 * @class Roo.Editor
32627 * @extends Roo.Component
32628 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
32630 * Create a new Editor
32631 * @param {Roo.form.Field} field The Field object (or descendant)
32632 * @param {Object} config The config object
32634 Roo.Editor = function(field, config){
32635 Roo.Editor.superclass.constructor.call(this, config);
32636 this.field = field;
32639 * @event beforestartedit
32640 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
32641 * false from the handler of this event.
32642 * @param {Editor} this
32643 * @param {Roo.Element} boundEl The underlying element bound to this editor
32644 * @param {Mixed} value The field value being set
32646 "beforestartedit" : true,
32649 * Fires when this editor is displayed
32650 * @param {Roo.Element} boundEl The underlying element bound to this editor
32651 * @param {Mixed} value The starting field value
32653 "startedit" : true,
32655 * @event beforecomplete
32656 * Fires after a change has been made to the field, but before the change is reflected in the underlying
32657 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
32658 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
32659 * event will not fire since no edit actually occurred.
32660 * @param {Editor} this
32661 * @param {Mixed} value The current field value
32662 * @param {Mixed} startValue The original field value
32664 "beforecomplete" : true,
32667 * Fires after editing is complete and any changed value has been written to the underlying field.
32668 * @param {Editor} this
32669 * @param {Mixed} value The current field value
32670 * @param {Mixed} startValue The original field value
32674 * @event specialkey
32675 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
32676 * {@link Roo.EventObject#getKey} to determine which key was pressed.
32677 * @param {Roo.form.Field} this
32678 * @param {Roo.EventObject} e The event object
32680 "specialkey" : true
32684 Roo.extend(Roo.Editor, Roo.Component, {
32686 * @cfg {Boolean/String} autosize
32687 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
32688 * or "height" to adopt the height only (defaults to false)
32691 * @cfg {Boolean} revertInvalid
32692 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
32693 * validation fails (defaults to true)
32696 * @cfg {Boolean} ignoreNoChange
32697 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
32698 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
32699 * will never be ignored.
32702 * @cfg {Boolean} hideEl
32703 * False to keep the bound element visible while the editor is displayed (defaults to true)
32706 * @cfg {Mixed} value
32707 * The data value of the underlying field (defaults to "")
32711 * @cfg {String} alignment
32712 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
32716 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
32717 * for bottom-right shadow (defaults to "frame")
32721 * @cfg {Boolean} constrain True to constrain the editor to the viewport
32725 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
32727 completeOnEnter : false,
32729 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
32731 cancelOnEsc : false,
32733 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
32738 onRender : function(ct, position){
32739 this.el = new Roo.Layer({
32740 shadow: this.shadow,
32746 constrain: this.constrain
32748 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
32749 if(this.field.msgTarget != 'title'){
32750 this.field.msgTarget = 'qtip';
32752 this.field.render(this.el);
32754 this.field.el.dom.setAttribute('autocomplete', 'off');
32756 this.field.on("specialkey", this.onSpecialKey, this);
32757 if(this.swallowKeys){
32758 this.field.el.swallowEvent(['keydown','keypress']);
32761 this.field.on("blur", this.onBlur, this);
32762 if(this.field.grow){
32763 this.field.on("autosize", this.el.sync, this.el, {delay:1});
32767 onSpecialKey : function(field, e)
32769 //Roo.log('editor onSpecialKey');
32770 if(this.completeOnEnter && e.getKey() == e.ENTER){
32772 this.completeEdit();
32775 // do not fire special key otherwise it might hide close the editor...
32776 if(e.getKey() == e.ENTER){
32779 if(this.cancelOnEsc && e.getKey() == e.ESC){
32783 this.fireEvent('specialkey', field, e);
32788 * Starts the editing process and shows the editor.
32789 * @param {String/HTMLElement/Element} el The element to edit
32790 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
32791 * to the innerHTML of el.
32793 startEdit : function(el, value){
32795 this.completeEdit();
32797 this.boundEl = Roo.get(el);
32798 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
32799 if(!this.rendered){
32800 this.render(this.parentEl || document.body);
32802 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
32805 this.startValue = v;
32806 this.field.setValue(v);
32808 var sz = this.boundEl.getSize();
32809 switch(this.autoSize){
32811 this.setSize(sz.width, "");
32814 this.setSize("", sz.height);
32817 this.setSize(sz.width, sz.height);
32820 this.el.alignTo(this.boundEl, this.alignment);
32821 this.editing = true;
32823 Roo.QuickTips.disable();
32829 * Sets the height and width of this editor.
32830 * @param {Number} width The new width
32831 * @param {Number} height The new height
32833 setSize : function(w, h){
32834 this.field.setSize(w, h);
32841 * Realigns the editor to the bound field based on the current alignment config value.
32843 realign : function(){
32844 this.el.alignTo(this.boundEl, this.alignment);
32848 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
32849 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
32851 completeEdit : function(remainVisible){
32855 var v = this.getValue();
32856 if(this.revertInvalid !== false && !this.field.isValid()){
32857 v = this.startValue;
32858 this.cancelEdit(true);
32860 if(String(v) === String(this.startValue) && this.ignoreNoChange){
32861 this.editing = false;
32865 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
32866 this.editing = false;
32867 if(this.updateEl && this.boundEl){
32868 this.boundEl.update(v);
32870 if(remainVisible !== true){
32873 this.fireEvent("complete", this, v, this.startValue);
32878 onShow : function(){
32880 if(this.hideEl !== false){
32881 this.boundEl.hide();
32884 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
32885 this.fixIEFocus = true;
32886 this.deferredFocus.defer(50, this);
32888 this.field.focus();
32890 this.fireEvent("startedit", this.boundEl, this.startValue);
32893 deferredFocus : function(){
32895 this.field.focus();
32900 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
32901 * reverted to the original starting value.
32902 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
32903 * cancel (defaults to false)
32905 cancelEdit : function(remainVisible){
32907 this.setValue(this.startValue);
32908 if(remainVisible !== true){
32915 onBlur : function(){
32916 if(this.allowBlur !== true && this.editing){
32917 this.completeEdit();
32922 onHide : function(){
32924 this.completeEdit();
32928 if(this.field.collapse){
32929 this.field.collapse();
32932 if(this.hideEl !== false){
32933 this.boundEl.show();
32936 Roo.QuickTips.enable();
32941 * Sets the data value of the editor
32942 * @param {Mixed} value Any valid value supported by the underlying field
32944 setValue : function(v){
32945 this.field.setValue(v);
32949 * Gets the data value of the editor
32950 * @return {Mixed} The data value
32952 getValue : function(){
32953 return this.field.getValue();
32957 * Ext JS Library 1.1.1
32958 * Copyright(c) 2006-2007, Ext JS, LLC.
32960 * Originally Released Under LGPL - original licence link has changed is not relivant.
32963 * <script type="text/javascript">
32967 * @class Roo.BasicDialog
32968 * @extends Roo.util.Observable
32969 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
32971 var dlg = new Roo.BasicDialog("my-dlg", {
32980 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
32981 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
32982 dlg.addButton('Cancel', dlg.hide, dlg);
32985 <b>A Dialog should always be a direct child of the body element.</b>
32986 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
32987 * @cfg {String} title Default text to display in the title bar (defaults to null)
32988 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
32989 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
32990 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
32991 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
32992 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
32993 * (defaults to null with no animation)
32994 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
32995 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
32996 * property for valid values (defaults to 'all')
32997 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
32998 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
32999 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
33000 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
33001 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
33002 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
33003 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
33004 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
33005 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
33006 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
33007 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
33008 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
33009 * draggable = true (defaults to false)
33010 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
33011 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
33012 * shadow (defaults to false)
33013 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
33014 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
33015 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
33016 * @cfg {Array} buttons Array of buttons
33017 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
33019 * Create a new BasicDialog.
33020 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
33021 * @param {Object} config Configuration options
33023 Roo.BasicDialog = function(el, config){
33024 this.el = Roo.get(el);
33025 var dh = Roo.DomHelper;
33026 if(!this.el && config && config.autoCreate){
33027 if(typeof config.autoCreate == "object"){
33028 if(!config.autoCreate.id){
33029 config.autoCreate.id = el;
33031 this.el = dh.append(document.body,
33032 config.autoCreate, true);
33034 this.el = dh.append(document.body,
33035 {tag: "div", id: el, style:'visibility:hidden;'}, true);
33039 el.setDisplayed(true);
33040 el.hide = this.hideAction;
33042 el.addClass("x-dlg");
33044 Roo.apply(this, config);
33046 this.proxy = el.createProxy("x-dlg-proxy");
33047 this.proxy.hide = this.hideAction;
33048 this.proxy.setOpacity(.5);
33052 el.setWidth(config.width);
33055 el.setHeight(config.height);
33057 this.size = el.getSize();
33058 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
33059 this.xy = [config.x,config.y];
33061 this.xy = el.getCenterXY(true);
33063 /** The header element @type Roo.Element */
33064 this.header = el.child("> .x-dlg-hd");
33065 /** The body element @type Roo.Element */
33066 this.body = el.child("> .x-dlg-bd");
33067 /** The footer element @type Roo.Element */
33068 this.footer = el.child("> .x-dlg-ft");
33071 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
33074 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
33077 this.header.unselectable();
33079 this.header.update(this.title);
33081 // this element allows the dialog to be focused for keyboard event
33082 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
33083 this.focusEl.swallowEvent("click", true);
33085 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
33087 // wrap the body and footer for special rendering
33088 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
33090 this.bwrap.dom.appendChild(this.footer.dom);
33093 this.bg = this.el.createChild({
33094 tag: "div", cls:"x-dlg-bg",
33095 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
33097 this.centerBg = this.bg.child("div.x-dlg-bg-center");
33100 if(this.autoScroll !== false && !this.autoTabs){
33101 this.body.setStyle("overflow", "auto");
33104 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
33106 if(this.closable !== false){
33107 this.el.addClass("x-dlg-closable");
33108 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
33109 this.close.on("click", this.closeClick, this);
33110 this.close.addClassOnOver("x-dlg-close-over");
33112 if(this.collapsible !== false){
33113 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
33114 this.collapseBtn.on("click", this.collapseClick, this);
33115 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
33116 this.header.on("dblclick", this.collapseClick, this);
33118 if(this.resizable !== false){
33119 this.el.addClass("x-dlg-resizable");
33120 this.resizer = new Roo.Resizable(el, {
33121 minWidth: this.minWidth || 80,
33122 minHeight:this.minHeight || 80,
33123 handles: this.resizeHandles || "all",
33126 this.resizer.on("beforeresize", this.beforeResize, this);
33127 this.resizer.on("resize", this.onResize, this);
33129 if(this.draggable !== false){
33130 el.addClass("x-dlg-draggable");
33131 if (!this.proxyDrag) {
33132 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
33135 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
33137 dd.setHandleElId(this.header.id);
33138 dd.endDrag = this.endMove.createDelegate(this);
33139 dd.startDrag = this.startMove.createDelegate(this);
33140 dd.onDrag = this.onDrag.createDelegate(this);
33145 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
33146 this.mask.enableDisplayMode("block");
33148 this.el.addClass("x-dlg-modal");
33151 this.shadow = new Roo.Shadow({
33152 mode : typeof this.shadow == "string" ? this.shadow : "sides",
33153 offset : this.shadowOffset
33156 this.shadowOffset = 0;
33158 if(Roo.useShims && this.shim !== false){
33159 this.shim = this.el.createShim();
33160 this.shim.hide = this.hideAction;
33168 if (this.buttons) {
33169 var bts= this.buttons;
33171 Roo.each(bts, function(b) {
33180 * Fires when a key is pressed
33181 * @param {Roo.BasicDialog} this
33182 * @param {Roo.EventObject} e
33187 * Fires when this dialog is moved by the user.
33188 * @param {Roo.BasicDialog} this
33189 * @param {Number} x The new page X
33190 * @param {Number} y The new page Y
33195 * Fires when this dialog is resized by the user.
33196 * @param {Roo.BasicDialog} this
33197 * @param {Number} width The new width
33198 * @param {Number} height The new height
33202 * @event beforehide
33203 * Fires before this dialog is hidden.
33204 * @param {Roo.BasicDialog} this
33206 "beforehide" : true,
33209 * Fires when this dialog is hidden.
33210 * @param {Roo.BasicDialog} this
33214 * @event beforeshow
33215 * Fires before this dialog is shown.
33216 * @param {Roo.BasicDialog} this
33218 "beforeshow" : true,
33221 * Fires when this dialog is shown.
33222 * @param {Roo.BasicDialog} this
33226 el.on("keydown", this.onKeyDown, this);
33227 el.on("mousedown", this.toFront, this);
33228 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
33230 Roo.DialogManager.register(this);
33231 Roo.BasicDialog.superclass.constructor.call(this);
33234 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
33235 shadowOffset: Roo.isIE ? 6 : 5,
33238 minButtonWidth: 75,
33239 defaultButton: null,
33240 buttonAlign: "right",
33245 * Sets the dialog title text
33246 * @param {String} text The title text to display
33247 * @return {Roo.BasicDialog} this
33249 setTitle : function(text){
33250 this.header.update(text);
33255 closeClick : function(){
33260 collapseClick : function(){
33261 this[this.collapsed ? "expand" : "collapse"]();
33265 * Collapses the dialog to its minimized state (only the title bar is visible).
33266 * Equivalent to the user clicking the collapse dialog button.
33268 collapse : function(){
33269 if(!this.collapsed){
33270 this.collapsed = true;
33271 this.el.addClass("x-dlg-collapsed");
33272 this.restoreHeight = this.el.getHeight();
33273 this.resizeTo(this.el.getWidth(), this.header.getHeight());
33278 * Expands a collapsed dialog back to its normal state. Equivalent to the user
33279 * clicking the expand dialog button.
33281 expand : function(){
33282 if(this.collapsed){
33283 this.collapsed = false;
33284 this.el.removeClass("x-dlg-collapsed");
33285 this.resizeTo(this.el.getWidth(), this.restoreHeight);
33290 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
33291 * @return {Roo.TabPanel} The tabs component
33293 initTabs : function(){
33294 var tabs = this.getTabs();
33295 while(tabs.getTab(0)){
33298 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
33300 tabs.addTab(Roo.id(dom), dom.title);
33308 beforeResize : function(){
33309 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
33313 onResize : function(){
33314 this.refreshSize();
33315 this.syncBodyHeight();
33316 this.adjustAssets();
33318 this.fireEvent("resize", this, this.size.width, this.size.height);
33322 onKeyDown : function(e){
33323 if(this.isVisible()){
33324 this.fireEvent("keydown", this, e);
33329 * Resizes the dialog.
33330 * @param {Number} width
33331 * @param {Number} height
33332 * @return {Roo.BasicDialog} this
33334 resizeTo : function(width, height){
33335 this.el.setSize(width, height);
33336 this.size = {width: width, height: height};
33337 this.syncBodyHeight();
33338 if(this.fixedcenter){
33341 if(this.isVisible()){
33342 this.constrainXY();
33343 this.adjustAssets();
33345 this.fireEvent("resize", this, width, height);
33351 * Resizes the dialog to fit the specified content size.
33352 * @param {Number} width
33353 * @param {Number} height
33354 * @return {Roo.BasicDialog} this
33356 setContentSize : function(w, h){
33357 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
33358 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
33359 //if(!this.el.isBorderBox()){
33360 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
33361 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
33364 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
33365 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
33367 this.resizeTo(w, h);
33372 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
33373 * executed in response to a particular key being pressed while the dialog is active.
33374 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
33375 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
33376 * @param {Function} fn The function to call
33377 * @param {Object} scope (optional) The scope of the function
33378 * @return {Roo.BasicDialog} this
33380 addKeyListener : function(key, fn, scope){
33381 var keyCode, shift, ctrl, alt;
33382 if(typeof key == "object" && !(key instanceof Array)){
33383 keyCode = key["key"];
33384 shift = key["shift"];
33385 ctrl = key["ctrl"];
33390 var handler = function(dlg, e){
33391 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
33392 var k = e.getKey();
33393 if(keyCode instanceof Array){
33394 for(var i = 0, len = keyCode.length; i < len; i++){
33395 if(keyCode[i] == k){
33396 fn.call(scope || window, dlg, k, e);
33402 fn.call(scope || window, dlg, k, e);
33407 this.on("keydown", handler);
33412 * Returns the TabPanel component (creates it if it doesn't exist).
33413 * Note: If you wish to simply check for the existence of tabs without creating them,
33414 * check for a null 'tabs' property.
33415 * @return {Roo.TabPanel} The tabs component
33417 getTabs : function(){
33419 this.el.addClass("x-dlg-auto-tabs");
33420 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
33421 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
33427 * Adds a button to the footer section of the dialog.
33428 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
33429 * object or a valid Roo.DomHelper element config
33430 * @param {Function} handler The function called when the button is clicked
33431 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
33432 * @return {Roo.Button} The new button
33434 addButton : function(config, handler, scope){
33435 var dh = Roo.DomHelper;
33437 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
33439 if(!this.btnContainer){
33440 var tb = this.footer.createChild({
33442 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
33443 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
33445 this.btnContainer = tb.firstChild.firstChild.firstChild;
33450 minWidth: this.minButtonWidth,
33453 if(typeof config == "string"){
33454 bconfig.text = config;
33457 bconfig.dhconfig = config;
33459 Roo.apply(bconfig, config);
33463 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
33464 bconfig.position = Math.max(0, bconfig.position);
33465 fc = this.btnContainer.childNodes[bconfig.position];
33468 var btn = new Roo.Button(
33470 this.btnContainer.insertBefore(document.createElement("td"),fc)
33471 : this.btnContainer.appendChild(document.createElement("td")),
33472 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
33475 this.syncBodyHeight();
33478 * Array of all the buttons that have been added to this dialog via addButton
33483 this.buttons.push(btn);
33488 * Sets the default button to be focused when the dialog is displayed.
33489 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
33490 * @return {Roo.BasicDialog} this
33492 setDefaultButton : function(btn){
33493 this.defaultButton = btn;
33498 getHeaderFooterHeight : function(safe){
33501 height += this.header.getHeight();
33504 var fm = this.footer.getMargins();
33505 height += (this.footer.getHeight()+fm.top+fm.bottom);
33507 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
33508 height += this.centerBg.getPadding("tb");
33513 syncBodyHeight : function()
33515 var bd = this.body, // the text
33516 cb = this.centerBg, // wrapper around bottom.. but does not seem to be used..
33518 var height = this.size.height - this.getHeaderFooterHeight(false);
33519 bd.setHeight(height-bd.getMargins("tb"));
33520 var hh = this.header.getHeight();
33521 var h = this.size.height-hh;
33524 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
33525 bw.setHeight(h-cb.getPadding("tb"));
33527 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
33528 bd.setWidth(bw.getWidth(true));
33530 this.tabs.syncHeight();
33532 this.tabs.el.repaint();
33538 * Restores the previous state of the dialog if Roo.state is configured.
33539 * @return {Roo.BasicDialog} this
33541 restoreState : function(){
33542 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
33543 if(box && box.width){
33544 this.xy = [box.x, box.y];
33545 this.resizeTo(box.width, box.height);
33551 beforeShow : function(){
33553 if(this.fixedcenter){
33554 this.xy = this.el.getCenterXY(true);
33557 Roo.get(document.body).addClass("x-body-masked");
33558 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
33561 this.constrainXY();
33565 animShow : function(){
33566 var b = Roo.get(this.animateTarget).getBox();
33567 this.proxy.setSize(b.width, b.height);
33568 this.proxy.setLocation(b.x, b.y);
33570 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
33571 true, .35, this.showEl.createDelegate(this));
33575 * Shows the dialog.
33576 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
33577 * @return {Roo.BasicDialog} this
33579 show : function(animateTarget){
33580 if (this.fireEvent("beforeshow", this) === false){
33583 if(this.syncHeightBeforeShow){
33584 this.syncBodyHeight();
33585 }else if(this.firstShow){
33586 this.firstShow = false;
33587 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
33589 this.animateTarget = animateTarget || this.animateTarget;
33590 if(!this.el.isVisible()){
33592 if(this.animateTarget && Roo.get(this.animateTarget)){
33602 showEl : function(){
33604 this.el.setXY(this.xy);
33606 this.adjustAssets(true);
33609 // IE peekaboo bug - fix found by Dave Fenwick
33613 this.fireEvent("show", this);
33617 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
33618 * dialog itself will receive focus.
33620 focus : function(){
33621 if(this.defaultButton){
33622 this.defaultButton.focus();
33624 this.focusEl.focus();
33629 constrainXY : function(){
33630 if(this.constraintoviewport !== false){
33631 if(!this.viewSize){
33632 if(this.container){
33633 var s = this.container.getSize();
33634 this.viewSize = [s.width, s.height];
33636 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
33639 var s = Roo.get(this.container||document).getScroll();
33641 var x = this.xy[0], y = this.xy[1];
33642 var w = this.size.width, h = this.size.height;
33643 var vw = this.viewSize[0], vh = this.viewSize[1];
33644 // only move it if it needs it
33646 // first validate right/bottom
33647 if(x + w > vw+s.left){
33651 if(y + h > vh+s.top){
33655 // then make sure top/left isn't negative
33667 if(this.isVisible()){
33668 this.el.setLocation(x, y);
33669 this.adjustAssets();
33676 onDrag : function(){
33677 if(!this.proxyDrag){
33678 this.xy = this.el.getXY();
33679 this.adjustAssets();
33684 adjustAssets : function(doShow){
33685 var x = this.xy[0], y = this.xy[1];
33686 var w = this.size.width, h = this.size.height;
33687 if(doShow === true){
33689 this.shadow.show(this.el);
33695 if(this.shadow && this.shadow.isVisible()){
33696 this.shadow.show(this.el);
33698 if(this.shim && this.shim.isVisible()){
33699 this.shim.setBounds(x, y, w, h);
33704 adjustViewport : function(w, h){
33706 w = Roo.lib.Dom.getViewWidth();
33707 h = Roo.lib.Dom.getViewHeight();
33710 this.viewSize = [w, h];
33711 if(this.modal && this.mask.isVisible()){
33712 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
33713 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
33715 if(this.isVisible()){
33716 this.constrainXY();
33721 * Destroys this dialog and all its supporting elements (including any tabs, shim,
33722 * shadow, proxy, mask, etc.) Also removes all event listeners.
33723 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
33725 destroy : function(removeEl){
33726 if(this.isVisible()){
33727 this.animateTarget = null;
33730 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
33732 this.tabs.destroy(removeEl);
33745 for(var i = 0, len = this.buttons.length; i < len; i++){
33746 this.buttons[i].destroy();
33749 this.el.removeAllListeners();
33750 if(removeEl === true){
33751 this.el.update("");
33754 Roo.DialogManager.unregister(this);
33758 startMove : function(){
33759 if(this.proxyDrag){
33762 if(this.constraintoviewport !== false){
33763 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
33768 endMove : function(){
33769 if(!this.proxyDrag){
33770 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
33772 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
33775 this.refreshSize();
33776 this.adjustAssets();
33778 this.fireEvent("move", this, this.xy[0], this.xy[1]);
33782 * Brings this dialog to the front of any other visible dialogs
33783 * @return {Roo.BasicDialog} this
33785 toFront : function(){
33786 Roo.DialogManager.bringToFront(this);
33791 * Sends this dialog to the back (under) of any other visible dialogs
33792 * @return {Roo.BasicDialog} this
33794 toBack : function(){
33795 Roo.DialogManager.sendToBack(this);
33800 * Centers this dialog in the viewport
33801 * @return {Roo.BasicDialog} this
33803 center : function(){
33804 var xy = this.el.getCenterXY(true);
33805 this.moveTo(xy[0], xy[1]);
33810 * Moves the dialog's top-left corner to the specified point
33811 * @param {Number} x
33812 * @param {Number} y
33813 * @return {Roo.BasicDialog} this
33815 moveTo : function(x, y){
33817 if(this.isVisible()){
33818 this.el.setXY(this.xy);
33819 this.adjustAssets();
33825 * Aligns the dialog to the specified element
33826 * @param {String/HTMLElement/Roo.Element} element The element to align to.
33827 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
33828 * @param {Array} offsets (optional) Offset the positioning by [x, y]
33829 * @return {Roo.BasicDialog} this
33831 alignTo : function(element, position, offsets){
33832 this.xy = this.el.getAlignToXY(element, position, offsets);
33833 if(this.isVisible()){
33834 this.el.setXY(this.xy);
33835 this.adjustAssets();
33841 * Anchors an element to another element and realigns it when the window is resized.
33842 * @param {String/HTMLElement/Roo.Element} element The element to align to.
33843 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
33844 * @param {Array} offsets (optional) Offset the positioning by [x, y]
33845 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
33846 * is a number, it is used as the buffer delay (defaults to 50ms).
33847 * @return {Roo.BasicDialog} this
33849 anchorTo : function(el, alignment, offsets, monitorScroll){
33850 var action = function(){
33851 this.alignTo(el, alignment, offsets);
33853 Roo.EventManager.onWindowResize(action, this);
33854 var tm = typeof monitorScroll;
33855 if(tm != 'undefined'){
33856 Roo.EventManager.on(window, 'scroll', action, this,
33857 {buffer: tm == 'number' ? monitorScroll : 50});
33864 * Returns true if the dialog is visible
33865 * @return {Boolean}
33867 isVisible : function(){
33868 return this.el.isVisible();
33872 animHide : function(callback){
33873 var b = Roo.get(this.animateTarget).getBox();
33875 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
33877 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
33878 this.hideEl.createDelegate(this, [callback]));
33882 * Hides the dialog.
33883 * @param {Function} callback (optional) Function to call when the dialog is hidden
33884 * @return {Roo.BasicDialog} this
33886 hide : function(callback){
33887 if (this.fireEvent("beforehide", this) === false){
33891 this.shadow.hide();
33896 // sometimes animateTarget seems to get set.. causing problems...
33897 // this just double checks..
33898 if(this.animateTarget && Roo.get(this.animateTarget)) {
33899 this.animHide(callback);
33902 this.hideEl(callback);
33908 hideEl : function(callback){
33912 Roo.get(document.body).removeClass("x-body-masked");
33914 this.fireEvent("hide", this);
33915 if(typeof callback == "function"){
33921 hideAction : function(){
33922 this.setLeft("-10000px");
33923 this.setTop("-10000px");
33924 this.setStyle("visibility", "hidden");
33928 refreshSize : function(){
33929 this.size = this.el.getSize();
33930 this.xy = this.el.getXY();
33931 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
33935 // z-index is managed by the DialogManager and may be overwritten at any time
33936 setZIndex : function(index){
33938 this.mask.setStyle("z-index", index);
33941 this.shim.setStyle("z-index", ++index);
33944 this.shadow.setZIndex(++index);
33946 this.el.setStyle("z-index", ++index);
33948 this.proxy.setStyle("z-index", ++index);
33951 this.resizer.proxy.setStyle("z-index", ++index);
33954 this.lastZIndex = index;
33958 * Returns the element for this dialog
33959 * @return {Roo.Element} The underlying dialog Element
33961 getEl : function(){
33967 * @class Roo.DialogManager
33968 * Provides global access to BasicDialogs that have been created and
33969 * support for z-indexing (layering) multiple open dialogs.
33971 Roo.DialogManager = function(){
33973 var accessList = [];
33977 var sortDialogs = function(d1, d2){
33978 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
33982 var orderDialogs = function(){
33983 accessList.sort(sortDialogs);
33984 var seed = Roo.DialogManager.zseed;
33985 for(var i = 0, len = accessList.length; i < len; i++){
33986 var dlg = accessList[i];
33988 dlg.setZIndex(seed + (i*10));
33995 * The starting z-index for BasicDialogs (defaults to 9000)
33996 * @type Number The z-index value
34001 register : function(dlg){
34002 list[dlg.id] = dlg;
34003 accessList.push(dlg);
34007 unregister : function(dlg){
34008 delete list[dlg.id];
34011 if(!accessList.indexOf){
34012 for( i = 0, len = accessList.length; i < len; i++){
34013 if(accessList[i] == dlg){
34014 accessList.splice(i, 1);
34019 i = accessList.indexOf(dlg);
34021 accessList.splice(i, 1);
34027 * Gets a registered dialog by id
34028 * @param {String/Object} id The id of the dialog or a dialog
34029 * @return {Roo.BasicDialog} this
34031 get : function(id){
34032 return typeof id == "object" ? id : list[id];
34036 * Brings the specified dialog to the front
34037 * @param {String/Object} dlg The id of the dialog or a dialog
34038 * @return {Roo.BasicDialog} this
34040 bringToFront : function(dlg){
34041 dlg = this.get(dlg);
34044 dlg._lastAccess = new Date().getTime();
34051 * Sends the specified dialog to the back
34052 * @param {String/Object} dlg The id of the dialog or a dialog
34053 * @return {Roo.BasicDialog} this
34055 sendToBack : function(dlg){
34056 dlg = this.get(dlg);
34057 dlg._lastAccess = -(new Date().getTime());
34063 * Hides all dialogs
34065 hideAll : function(){
34066 for(var id in list){
34067 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
34076 * @class Roo.LayoutDialog
34077 * @extends Roo.BasicDialog
34078 * @children Roo.ContentPanel
34079 * @parent builder none
34080 * Dialog which provides adjustments for working with a layout in a Dialog.
34081 * Add your necessary layout config options to the dialog's config.<br>
34082 * Example usage (including a nested layout):
34085 dialog = new Roo.LayoutDialog("download-dlg", {
34094 // layout config merges with the dialog config
34096 tabPosition: "top",
34097 alwaysShowTabs: true
34100 dialog.addKeyListener(27, dialog.hide, dialog);
34101 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
34102 dialog.addButton("Build It!", this.getDownload, this);
34104 // we can even add nested layouts
34105 var innerLayout = new Roo.BorderLayout("dl-inner", {
34115 innerLayout.beginUpdate();
34116 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
34117 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
34118 innerLayout.endUpdate(true);
34120 var layout = dialog.getLayout();
34121 layout.beginUpdate();
34122 layout.add("center", new Roo.ContentPanel("standard-panel",
34123 {title: "Download the Source", fitToFrame:true}));
34124 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
34125 {title: "Build your own roo.js"}));
34126 layout.getRegion("center").showPanel(sp);
34127 layout.endUpdate();
34131 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
34132 * @param {Object} config configuration options
34134 Roo.LayoutDialog = function(el, cfg){
34137 if (typeof(cfg) == 'undefined') {
34138 config = Roo.apply({}, el);
34139 // not sure why we use documentElement here.. - it should always be body.
34140 // IE7 borks horribly if we use documentElement.
34141 // webkit also does not like documentElement - it creates a body element...
34142 el = Roo.get( document.body || document.documentElement ).createChild();
34143 //config.autoCreate = true;
34147 config.autoTabs = false;
34148 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
34149 this.body.setStyle({overflow:"hidden", position:"relative"});
34150 this.layout = new Roo.BorderLayout(this.body.dom, config);
34151 this.layout.monitorWindowResize = false;
34152 this.el.addClass("x-dlg-auto-layout");
34153 // fix case when center region overwrites center function
34154 this.center = Roo.BasicDialog.prototype.center;
34155 this.on("show", this.layout.layout, this.layout, true);
34156 if (config.items) {
34157 var xitems = config.items;
34158 delete config.items;
34159 Roo.each(xitems, this.addxtype, this);
34164 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
34168 * @cfg {Roo.LayoutRegion} east
34171 * @cfg {Roo.LayoutRegion} west
34174 * @cfg {Roo.LayoutRegion} south
34177 * @cfg {Roo.LayoutRegion} north
34180 * @cfg {Roo.LayoutRegion} center
34183 * @cfg {Roo.Button} buttons[] Bottom buttons..
34188 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
34191 endUpdate : function(){
34192 this.layout.endUpdate();
34196 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
34199 beginUpdate : function(){
34200 this.layout.beginUpdate();
34204 * Get the BorderLayout for this dialog
34205 * @return {Roo.BorderLayout}
34207 getLayout : function(){
34208 return this.layout;
34211 showEl : function(){
34212 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
34214 this.layout.layout();
34219 // Use the syncHeightBeforeShow config option to control this automatically
34220 syncBodyHeight : function(){
34221 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
34222 if(this.layout){this.layout.layout();}
34226 * Add an xtype element (actually adds to the layout.)
34227 * @return {Object} xdata xtype object data.
34230 addxtype : function(c) {
34231 return this.layout.addxtype(c);
34235 * Ext JS Library 1.1.1
34236 * Copyright(c) 2006-2007, Ext JS, LLC.
34238 * Originally Released Under LGPL - original licence link has changed is not relivant.
34241 * <script type="text/javascript">
34245 * @class Roo.MessageBox
34246 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
34250 Roo.Msg.alert('Status', 'Changes saved successfully.');
34252 // Prompt for user data:
34253 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
34255 // process text value...
34259 // Show a dialog using config options:
34261 title:'Save Changes?',
34262 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
34263 buttons: Roo.Msg.YESNOCANCEL,
34270 Roo.MessageBox = function(){
34271 var dlg, opt, mask, waitTimer;
34272 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
34273 var buttons, activeTextEl, bwidth;
34276 var handleButton = function(button){
34278 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
34282 var handleHide = function(){
34283 if(opt && opt.cls){
34284 dlg.el.removeClass(opt.cls);
34287 Roo.TaskMgr.stop(waitTimer);
34293 var updateButtons = function(b){
34296 buttons["ok"].hide();
34297 buttons["cancel"].hide();
34298 buttons["yes"].hide();
34299 buttons["no"].hide();
34300 dlg.footer.dom.style.display = 'none';
34303 dlg.footer.dom.style.display = '';
34304 for(var k in buttons){
34305 if(typeof buttons[k] != "function"){
34308 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
34309 width += buttons[k].el.getWidth()+15;
34319 var handleEsc = function(d, k, e){
34320 if(opt && opt.closable !== false){
34330 * Returns a reference to the underlying {@link Roo.BasicDialog} element
34331 * @return {Roo.BasicDialog} The BasicDialog element
34333 getDialog : function(){
34335 dlg = new Roo.BasicDialog("x-msg-box", {
34340 constraintoviewport:false,
34342 collapsible : false,
34345 width:400, height:100,
34346 buttonAlign:"center",
34347 closeClick : function(){
34348 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
34349 handleButton("no");
34351 handleButton("cancel");
34355 dlg.on("hide", handleHide);
34357 dlg.addKeyListener(27, handleEsc);
34359 var bt = this.buttonText;
34360 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
34361 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
34362 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
34363 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
34364 bodyEl = dlg.body.createChild({
34366 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>'
34368 msgEl = bodyEl.dom.firstChild;
34369 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
34370 textboxEl.enableDisplayMode();
34371 textboxEl.addKeyListener([10,13], function(){
34372 if(dlg.isVisible() && opt && opt.buttons){
34373 if(opt.buttons.ok){
34374 handleButton("ok");
34375 }else if(opt.buttons.yes){
34376 handleButton("yes");
34380 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
34381 textareaEl.enableDisplayMode();
34382 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
34383 progressEl.enableDisplayMode();
34384 var pf = progressEl.dom.firstChild;
34386 pp = Roo.get(pf.firstChild);
34387 pp.setHeight(pf.offsetHeight);
34395 * Updates the message box body text
34396 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
34397 * the XHTML-compliant non-breaking space character '&#160;')
34398 * @return {Roo.MessageBox} This message box
34400 updateText : function(text){
34401 if(!dlg.isVisible() && !opt.width){
34402 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
34404 msgEl.innerHTML = text || ' ';
34406 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
34407 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
34409 Math.min(opt.width || cw , this.maxWidth),
34410 Math.max(opt.minWidth || this.minWidth, bwidth)
34413 activeTextEl.setWidth(w);
34415 if(dlg.isVisible()){
34416 dlg.fixedcenter = false;
34418 // to big, make it scroll. = But as usual stupid IE does not support
34421 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
34422 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
34423 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
34425 bodyEl.dom.style.height = '';
34426 bodyEl.dom.style.overflowY = '';
34429 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
34431 bodyEl.dom.style.overflowX = '';
34434 dlg.setContentSize(w, bodyEl.getHeight());
34435 if(dlg.isVisible()){
34436 dlg.fixedcenter = true;
34442 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
34443 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
34444 * @param {Number} value Any number between 0 and 1 (e.g., .5)
34445 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
34446 * @return {Roo.MessageBox} This message box
34448 updateProgress : function(value, text){
34450 this.updateText(text);
34452 if (pp) { // weird bug on my firefox - for some reason this is not defined
34453 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
34459 * Returns true if the message box is currently displayed
34460 * @return {Boolean} True if the message box is visible, else false
34462 isVisible : function(){
34463 return dlg && dlg.isVisible();
34467 * Hides the message box if it is displayed
34470 if(this.isVisible()){
34476 * Displays a new message box, or reinitializes an existing message box, based on the config options
34477 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
34478 * The following config object properties are supported:
34480 Property Type Description
34481 ---------- --------------- ------------------------------------------------------------------------------------
34482 animEl String/Element An id or Element from which the message box should animate as it opens and
34483 closes (defaults to undefined)
34484 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
34485 cancel:'Bar'}), or false to not show any buttons (defaults to false)
34486 closable Boolean False to hide the top-right close button (defaults to true). Note that
34487 progress and wait dialogs will ignore this property and always hide the
34488 close button as they can only be closed programmatically.
34489 cls String A custom CSS class to apply to the message box element
34490 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
34491 displayed (defaults to 75)
34492 fn Function A callback function to execute after closing the dialog. The arguments to the
34493 function will be btn (the name of the button that was clicked, if applicable,
34494 e.g. "ok"), and text (the value of the active text field, if applicable).
34495 Progress and wait dialogs will ignore this option since they do not respond to
34496 user actions and can only be closed programmatically, so any required function
34497 should be called by the same code after it closes the dialog.
34498 icon String A CSS class that provides a background image to be used as an icon for
34499 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
34500 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
34501 minWidth Number The minimum width in pixels of the message box (defaults to 100)
34502 modal Boolean False to allow user interaction with the page while the message box is
34503 displayed (defaults to true)
34504 msg String A string that will replace the existing message box body text (defaults
34505 to the XHTML-compliant non-breaking space character ' ')
34506 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
34507 progress Boolean True to display a progress bar (defaults to false)
34508 progressText String The text to display inside the progress bar if progress = true (defaults to '')
34509 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
34510 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
34511 title String The title text
34512 value String The string value to set into the active textbox element if displayed
34513 wait Boolean True to display a progress bar (defaults to false)
34514 width Number The width of the dialog in pixels
34521 msg: 'Please enter your address:',
34523 buttons: Roo.MessageBox.OKCANCEL,
34526 animEl: 'addAddressBtn'
34529 * @param {Object} config Configuration options
34530 * @return {Roo.MessageBox} This message box
34532 show : function(options)
34535 // this causes nightmares if you show one dialog after another
34536 // especially on callbacks..
34538 if(this.isVisible()){
34541 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
34542 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
34543 Roo.log("New Dialog Message:" + options.msg )
34544 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
34545 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
34548 var d = this.getDialog();
34550 d.setTitle(opt.title || " ");
34551 d.close.setDisplayed(opt.closable !== false);
34552 activeTextEl = textboxEl;
34553 opt.prompt = opt.prompt || (opt.multiline ? true : false);
34558 textareaEl.setHeight(typeof opt.multiline == "number" ?
34559 opt.multiline : this.defaultTextHeight);
34560 activeTextEl = textareaEl;
34569 progressEl.setDisplayed(opt.progress === true);
34570 this.updateProgress(0);
34571 activeTextEl.dom.value = opt.value || "";
34573 dlg.setDefaultButton(activeTextEl);
34575 var bs = opt.buttons;
34578 db = buttons["ok"];
34579 }else if(bs && bs.yes){
34580 db = buttons["yes"];
34582 dlg.setDefaultButton(db);
34584 bwidth = updateButtons(opt.buttons);
34585 this.updateText(opt.msg);
34587 d.el.addClass(opt.cls);
34589 d.proxyDrag = opt.proxyDrag === true;
34590 d.modal = opt.modal !== false;
34591 d.mask = opt.modal !== false ? mask : false;
34592 if(!d.isVisible()){
34593 // force it to the end of the z-index stack so it gets a cursor in FF
34594 document.body.appendChild(dlg.el.dom);
34595 d.animateTarget = null;
34596 d.show(options.animEl);
34602 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
34603 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
34604 * and closing the message box when the process is complete.
34605 * @param {String} title The title bar text
34606 * @param {String} msg The message box body text
34607 * @return {Roo.MessageBox} This message box
34609 progress : function(title, msg){
34616 minWidth: this.minProgressWidth,
34623 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
34624 * If a callback function is passed it will be called after the user clicks the button, and the
34625 * id of the button that was clicked will be passed as the only parameter to the callback
34626 * (could also be the top-right close button).
34627 * @param {String} title The title bar text
34628 * @param {String} msg The message box body text
34629 * @param {Function} fn (optional) The callback function invoked after the message box is closed
34630 * @param {Object} scope (optional) The scope of the callback function
34631 * @return {Roo.MessageBox} This message box
34633 alert : function(title, msg, fn, scope){
34646 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
34647 * interaction while waiting for a long-running process to complete that does not have defined intervals.
34648 * You are responsible for closing the message box when the process is complete.
34649 * @param {String} msg The message box body text
34650 * @param {String} title (optional) The title bar text
34651 * @return {Roo.MessageBox} This message box
34653 wait : function(msg, title){
34664 waitTimer = Roo.TaskMgr.start({
34666 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
34674 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
34675 * If a callback function is passed it will be called after the user clicks either button, and the id of the
34676 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
34677 * @param {String} title The title bar text
34678 * @param {String} msg The message box body text
34679 * @param {Function} fn (optional) The callback function invoked after the message box is closed
34680 * @param {Object} scope (optional) The scope of the callback function
34681 * @return {Roo.MessageBox} This message box
34683 confirm : function(title, msg, fn, scope){
34687 buttons: this.YESNO,
34696 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
34697 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
34698 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
34699 * (could also be the top-right close button) and the text that was entered will be passed as the two
34700 * parameters to the callback.
34701 * @param {String} title The title bar text
34702 * @param {String} msg The message box body text
34703 * @param {Function} fn (optional) The callback function invoked after the message box is closed
34704 * @param {Object} scope (optional) The scope of the callback function
34705 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
34706 * property, or the height in pixels to create the textbox (defaults to false / single-line)
34707 * @return {Roo.MessageBox} This message box
34709 prompt : function(title, msg, fn, scope, multiline){
34713 buttons: this.OKCANCEL,
34718 multiline: multiline,
34725 * Button config that displays a single OK button
34730 * Button config that displays Yes and No buttons
34733 YESNO : {yes:true, no:true},
34735 * Button config that displays OK and Cancel buttons
34738 OKCANCEL : {ok:true, cancel:true},
34740 * Button config that displays Yes, No and Cancel buttons
34743 YESNOCANCEL : {yes:true, no:true, cancel:true},
34746 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
34749 defaultTextHeight : 75,
34751 * The maximum width in pixels of the message box (defaults to 600)
34756 * The minimum width in pixels of the message box (defaults to 100)
34761 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
34762 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
34765 minProgressWidth : 250,
34767 * An object containing the default button text strings that can be overriden for localized language support.
34768 * Supported properties are: ok, cancel, yes and no.
34769 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
34782 * Shorthand for {@link Roo.MessageBox}
34784 Roo.Msg = Roo.MessageBox;/*
34786 * Ext JS Library 1.1.1
34787 * Copyright(c) 2006-2007, Ext JS, LLC.
34789 * Originally Released Under LGPL - original licence link has changed is not relivant.
34792 * <script type="text/javascript">
34795 * @class Roo.QuickTips
34796 * Provides attractive and customizable tooltips for any element.
34799 Roo.QuickTips = function(){
34800 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
34801 var ce, bd, xy, dd;
34802 var visible = false, disabled = true, inited = false;
34803 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
34805 var onOver = function(e){
34809 var t = e.getTarget();
34810 if(!t || t.nodeType !== 1 || t == document || t == document.body){
34813 if(ce && t == ce.el){
34814 clearTimeout(hideProc);
34817 if(t && tagEls[t.id]){
34818 tagEls[t.id].el = t;
34819 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
34822 var ttp, et = Roo.fly(t);
34823 var ns = cfg.namespace;
34824 if(tm.interceptTitles && t.title){
34827 t.removeAttribute("title");
34828 e.preventDefault();
34830 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute) || et.getAttributeNS(cfg.alt_namespace, cfg.attribute) ;
34833 showProc = show.defer(tm.showDelay, tm, [{
34835 text: ttp.replace(/\\n/g,'<br/>'),
34836 width: et.getAttributeNS(ns, cfg.width),
34837 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
34838 title: et.getAttributeNS(ns, cfg.title),
34839 cls: et.getAttributeNS(ns, cfg.cls)
34844 var onOut = function(e){
34845 clearTimeout(showProc);
34846 var t = e.getTarget();
34847 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
34848 hideProc = setTimeout(hide, tm.hideDelay);
34852 var onMove = function(e){
34858 if(tm.trackMouse && ce){
34863 var onDown = function(e){
34864 clearTimeout(showProc);
34865 clearTimeout(hideProc);
34867 if(tm.hideOnClick){
34870 tm.enable.defer(100, tm);
34875 var getPad = function(){
34876 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
34879 var show = function(o){
34883 clearTimeout(dismissProc);
34885 if(removeCls){ // in case manually hidden
34886 el.removeClass(removeCls);
34890 el.addClass(ce.cls);
34891 removeCls = ce.cls;
34894 tipTitle.update(ce.title);
34897 tipTitle.update('');
34900 el.dom.style.width = tm.maxWidth+'px';
34901 //tipBody.dom.style.width = '';
34902 tipBodyText.update(o.text);
34903 var p = getPad(), w = ce.width;
34905 var td = tipBodyText.dom;
34906 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
34907 if(aw > tm.maxWidth){
34909 }else if(aw < tm.minWidth){
34915 //tipBody.setWidth(w);
34916 el.setWidth(parseInt(w, 10) + p);
34917 if(ce.autoHide === false){
34918 close.setDisplayed(true);
34923 close.setDisplayed(false);
34929 el.avoidY = xy[1]-18;
34934 el.setStyle("visibility", "visible");
34935 el.fadeIn({callback: afterShow});
34941 var afterShow = function(){
34945 if(tm.autoDismiss && ce.autoHide !== false){
34946 dismissProc = setTimeout(hide, tm.autoDismissDelay);
34951 var hide = function(noanim){
34952 clearTimeout(dismissProc);
34953 clearTimeout(hideProc);
34955 if(el.isVisible()){
34957 if(noanim !== true && tm.animate){
34958 el.fadeOut({callback: afterHide});
34965 var afterHide = function(){
34968 el.removeClass(removeCls);
34975 * @cfg {Number} minWidth
34976 * The minimum width of the quick tip (defaults to 40)
34980 * @cfg {Number} maxWidth
34981 * The maximum width of the quick tip (defaults to 300)
34985 * @cfg {Boolean} interceptTitles
34986 * True to automatically use the element's DOM title value if available (defaults to false)
34988 interceptTitles : false,
34990 * @cfg {Boolean} trackMouse
34991 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
34993 trackMouse : false,
34995 * @cfg {Boolean} hideOnClick
34996 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
34998 hideOnClick : true,
35000 * @cfg {Number} showDelay
35001 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
35005 * @cfg {Number} hideDelay
35006 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
35010 * @cfg {Boolean} autoHide
35011 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
35012 * Used in conjunction with hideDelay.
35017 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
35018 * (defaults to true). Used in conjunction with autoDismissDelay.
35020 autoDismiss : true,
35023 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
35025 autoDismissDelay : 5000,
35027 * @cfg {Boolean} animate
35028 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
35033 * @cfg {String} title
35034 * Title text to display (defaults to ''). This can be any valid HTML markup.
35038 * @cfg {String} text
35039 * Body text to display (defaults to ''). This can be any valid HTML markup.
35043 * @cfg {String} cls
35044 * A CSS class to apply to the base quick tip element (defaults to '').
35048 * @cfg {Number} width
35049 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
35050 * minWidth or maxWidth.
35055 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
35056 * or display QuickTips in a page.
35059 tm = Roo.QuickTips;
35060 cfg = tm.tagConfig;
35062 if(!Roo.isReady){ // allow calling of init() before onReady
35063 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
35066 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
35067 el.fxDefaults = {stopFx: true};
35068 // maximum custom styling
35069 //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>');
35070 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>');
35071 tipTitle = el.child('h3');
35072 tipTitle.enableDisplayMode("block");
35073 tipBody = el.child('div.x-tip-bd');
35074 tipBodyText = el.child('div.x-tip-bd-inner');
35075 //bdLeft = el.child('div.x-tip-bd-left');
35076 //bdRight = el.child('div.x-tip-bd-right');
35077 close = el.child('div.x-tip-close');
35078 close.enableDisplayMode("block");
35079 close.on("click", hide);
35080 var d = Roo.get(document);
35081 d.on("mousedown", onDown);
35082 d.on("mouseover", onOver);
35083 d.on("mouseout", onOut);
35084 d.on("mousemove", onMove);
35085 esc = d.addKeyListener(27, hide);
35088 dd = el.initDD("default", null, {
35089 onDrag : function(){
35093 dd.setHandleElId(tipTitle.id);
35102 * Configures a new quick tip instance and assigns it to a target element. The following config options
35105 Property Type Description
35106 ---------- --------------------- ------------------------------------------------------------------------
35107 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
35109 * @param {Object} config The config object
35111 register : function(config){
35112 var cs = config instanceof Array ? config : arguments;
35113 for(var i = 0, len = cs.length; i < len; i++) {
35115 var target = c.target;
35117 if(target instanceof Array){
35118 for(var j = 0, jlen = target.length; j < jlen; j++){
35119 tagEls[target[j]] = c;
35122 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
35129 * Removes this quick tip from its element and destroys it.
35130 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
35132 unregister : function(el){
35133 delete tagEls[Roo.id(el)];
35137 * Enable this quick tip.
35139 enable : function(){
35140 if(inited && disabled){
35142 if(locks.length < 1){
35149 * Disable this quick tip.
35151 disable : function(){
35153 clearTimeout(showProc);
35154 clearTimeout(hideProc);
35155 clearTimeout(dismissProc);
35163 * Returns true if the quick tip is enabled, else false.
35165 isEnabled : function(){
35171 namespace : "roo", // was ext?? this may break..
35172 alt_namespace : "ext",
35173 attribute : "qtip",
35183 // backwards compat
35184 Roo.QuickTips.tips = Roo.QuickTips.register;/*
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">
35197 * @class Roo.tree.TreePanel
35198 * @extends Roo.data.Tree
35199 * @cfg {Roo.tree.TreeNode} root The root node
35200 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
35201 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
35202 * @cfg {Boolean} enableDD true to enable drag and drop
35203 * @cfg {Boolean} enableDrag true to enable just drag
35204 * @cfg {Boolean} enableDrop true to enable just drop
35205 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
35206 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
35207 * @cfg {String} ddGroup The DD group this TreePanel belongs to
35208 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
35209 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
35210 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
35211 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
35212 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
35213 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
35214 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
35215 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
35216 * @cfg {Roo.tree.TreeLoader} loader A TreeLoader for use with this TreePanel
35217 * @cfg {Roo.tree.TreeEditor} editor The TreeEditor to display when clicked.
35218 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
35219 * @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>
35220 * @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>
35223 * @param {String/HTMLElement/Element} el The container element
35224 * @param {Object} config
35226 Roo.tree.TreePanel = function(el, config){
35228 var loader = false;
35230 root = config.root;
35231 delete config.root;
35233 if (config.loader) {
35234 loader = config.loader;
35235 delete config.loader;
35238 Roo.apply(this, config);
35239 Roo.tree.TreePanel.superclass.constructor.call(this);
35240 this.el = Roo.get(el);
35241 this.el.addClass('x-tree');
35242 //console.log(root);
35244 this.setRootNode( Roo.factory(root, Roo.tree));
35247 this.loader = Roo.factory(loader, Roo.tree);
35250 * Read-only. The id of the container element becomes this TreePanel's id.
35252 this.id = this.el.id;
35255 * @event beforeload
35256 * Fires before a node is loaded, return false to cancel
35257 * @param {Node} node The node being loaded
35259 "beforeload" : true,
35262 * Fires when a node is loaded
35263 * @param {Node} node The node that was loaded
35267 * @event textchange
35268 * Fires when the text for a node is changed
35269 * @param {Node} node The node
35270 * @param {String} text The new text
35271 * @param {String} oldText The old text
35273 "textchange" : true,
35275 * @event beforeexpand
35276 * Fires before a node is expanded, return false to cancel.
35277 * @param {Node} node The node
35278 * @param {Boolean} deep
35279 * @param {Boolean} anim
35281 "beforeexpand" : true,
35283 * @event beforecollapse
35284 * Fires before a node is collapsed, return false to cancel.
35285 * @param {Node} node The node
35286 * @param {Boolean} deep
35287 * @param {Boolean} anim
35289 "beforecollapse" : true,
35292 * Fires when a node is expanded
35293 * @param {Node} node The node
35297 * @event disabledchange
35298 * Fires when the disabled status of a node changes
35299 * @param {Node} node The node
35300 * @param {Boolean} disabled
35302 "disabledchange" : true,
35305 * Fires when a node is collapsed
35306 * @param {Node} node The node
35310 * @event beforeclick
35311 * Fires before click processing on a node. Return false to cancel the default action.
35312 * @param {Node} node The node
35313 * @param {Roo.EventObject} e The event object
35315 "beforeclick":true,
35317 * @event checkchange
35318 * Fires when a node with a checkbox's checked property changes
35319 * @param {Node} this This node
35320 * @param {Boolean} checked
35322 "checkchange":true,
35325 * Fires when a node is clicked
35326 * @param {Node} node The node
35327 * @param {Roo.EventObject} e The event object
35332 * Fires when a node is double clicked
35333 * @param {Node} node The node
35334 * @param {Roo.EventObject} e The event object
35338 * @event contextmenu
35339 * Fires when a node is right clicked
35340 * @param {Node} node The node
35341 * @param {Roo.EventObject} e The event object
35343 "contextmenu":true,
35345 * @event beforechildrenrendered
35346 * Fires right before the child nodes for a node are rendered
35347 * @param {Node} node The node
35349 "beforechildrenrendered":true,
35352 * Fires when a node starts being dragged
35353 * @param {Roo.tree.TreePanel} this
35354 * @param {Roo.tree.TreeNode} node
35355 * @param {event} e The raw browser event
35357 "startdrag" : true,
35360 * Fires when a drag operation is complete
35361 * @param {Roo.tree.TreePanel} this
35362 * @param {Roo.tree.TreeNode} node
35363 * @param {event} e The raw browser event
35368 * Fires when a dragged node is dropped on a valid DD target
35369 * @param {Roo.tree.TreePanel} this
35370 * @param {Roo.tree.TreeNode} node
35371 * @param {DD} dd The dd it was dropped on
35372 * @param {event} e The raw browser event
35376 * @event beforenodedrop
35377 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
35378 * passed to handlers has the following properties:<br />
35379 * <ul style="padding:5px;padding-left:16px;">
35380 * <li>tree - The TreePanel</li>
35381 * <li>target - The node being targeted for the drop</li>
35382 * <li>data - The drag data from the drag source</li>
35383 * <li>point - The point of the drop - append, above or below</li>
35384 * <li>source - The drag source</li>
35385 * <li>rawEvent - Raw mouse event</li>
35386 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
35387 * to be inserted by setting them on this object.</li>
35388 * <li>cancel - Set this to true to cancel the drop.</li>
35390 * @param {Object} dropEvent
35392 "beforenodedrop" : true,
35395 * Fires after a DD object is dropped on a node in this tree. The dropEvent
35396 * passed to handlers has the following properties:<br />
35397 * <ul style="padding:5px;padding-left:16px;">
35398 * <li>tree - The TreePanel</li>
35399 * <li>target - The node being targeted for the drop</li>
35400 * <li>data - The drag data from the drag source</li>
35401 * <li>point - The point of the drop - append, above or below</li>
35402 * <li>source - The drag source</li>
35403 * <li>rawEvent - Raw mouse event</li>
35404 * <li>dropNode - Dropped node(s).</li>
35406 * @param {Object} dropEvent
35410 * @event nodedragover
35411 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
35412 * passed to handlers has the following properties:<br />
35413 * <ul style="padding:5px;padding-left:16px;">
35414 * <li>tree - The TreePanel</li>
35415 * <li>target - The node being targeted for the drop</li>
35416 * <li>data - The drag data from the drag source</li>
35417 * <li>point - The point of the drop - append, above or below</li>
35418 * <li>source - The drag source</li>
35419 * <li>rawEvent - Raw mouse event</li>
35420 * <li>dropNode - Drop node(s) provided by the source.</li>
35421 * <li>cancel - Set this to true to signal drop not allowed.</li>
35423 * @param {Object} dragOverEvent
35425 "nodedragover" : true,
35427 * @event appendnode
35428 * Fires when append node to the tree
35429 * @param {Roo.tree.TreePanel} this
35430 * @param {Roo.tree.TreeNode} node
35431 * @param {Number} index The index of the newly appended node
35433 "appendnode" : true
35436 if(this.singleExpand){
35437 this.on("beforeexpand", this.restrictExpand, this);
35440 this.editor.tree = this;
35441 this.editor = Roo.factory(this.editor, Roo.tree);
35444 if (this.selModel) {
35445 this.selModel = Roo.factory(this.selModel, Roo.tree);
35449 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
35450 rootVisible : true,
35451 animate: Roo.enableFx,
35454 hlDrop : Roo.enableFx,
35458 rendererTip: false,
35460 restrictExpand : function(node){
35461 var p = node.parentNode;
35463 if(p.expandedChild && p.expandedChild.parentNode == p){
35464 p.expandedChild.collapse();
35466 p.expandedChild = node;
35470 // private override
35471 setRootNode : function(node){
35472 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
35473 if(!this.rootVisible){
35474 node.ui = new Roo.tree.RootTreeNodeUI(node);
35480 * Returns the container element for this TreePanel
35482 getEl : function(){
35487 * Returns the default TreeLoader for this TreePanel
35489 getLoader : function(){
35490 return this.loader;
35496 expandAll : function(){
35497 this.root.expand(true);
35501 * Collapse all nodes
35503 collapseAll : function(){
35504 this.root.collapse(true);
35508 * Returns the selection model used by this TreePanel
35510 getSelectionModel : function(){
35511 if(!this.selModel){
35512 this.selModel = new Roo.tree.DefaultSelectionModel();
35514 return this.selModel;
35518 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
35519 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
35520 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
35523 getChecked : function(a, startNode){
35524 startNode = startNode || this.root;
35526 var f = function(){
35527 if(this.attributes.checked){
35528 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
35531 startNode.cascade(f);
35536 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
35537 * @param {String} path
35538 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
35539 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
35540 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
35542 expandPath : function(path, attr, callback){
35543 attr = attr || "id";
35544 var keys = path.split(this.pathSeparator);
35545 var curNode = this.root;
35546 if(curNode.attributes[attr] != keys[1]){ // invalid root
35548 callback(false, null);
35553 var f = function(){
35554 if(++index == keys.length){
35556 callback(true, curNode);
35560 var c = curNode.findChild(attr, keys[index]);
35563 callback(false, curNode);
35568 c.expand(false, false, f);
35570 curNode.expand(false, false, f);
35574 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
35575 * @param {String} path
35576 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
35577 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
35578 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
35580 selectPath : function(path, attr, callback){
35581 attr = attr || "id";
35582 var keys = path.split(this.pathSeparator);
35583 var v = keys.pop();
35584 if(keys.length > 0){
35585 var f = function(success, node){
35586 if(success && node){
35587 var n = node.findChild(attr, v);
35593 }else if(callback){
35594 callback(false, n);
35598 callback(false, n);
35602 this.expandPath(keys.join(this.pathSeparator), attr, f);
35604 this.root.select();
35606 callback(true, this.root);
35611 getTreeEl : function(){
35616 * Trigger rendering of this TreePanel
35618 render : function(){
35619 if (this.innerCt) {
35620 return this; // stop it rendering more than once!!
35623 this.innerCt = this.el.createChild({tag:"ul",
35624 cls:"x-tree-root-ct " +
35625 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
35627 if(this.containerScroll){
35628 Roo.dd.ScrollManager.register(this.el);
35630 if((this.enableDD || this.enableDrop) && !this.dropZone){
35632 * The dropZone used by this tree if drop is enabled
35633 * @type Roo.tree.TreeDropZone
35635 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
35636 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
35639 if((this.enableDD || this.enableDrag) && !this.dragZone){
35641 * The dragZone used by this tree if drag is enabled
35642 * @type Roo.tree.TreeDragZone
35644 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
35645 ddGroup: this.ddGroup || "TreeDD",
35646 scroll: this.ddScroll
35649 this.getSelectionModel().init(this);
35651 Roo.log("ROOT not set in tree");
35654 this.root.render();
35655 if(!this.rootVisible){
35656 this.root.renderChildren();
35662 * Ext JS Library 1.1.1
35663 * Copyright(c) 2006-2007, Ext JS, LLC.
35665 * Originally Released Under LGPL - original licence link has changed is not relivant.
35668 * <script type="text/javascript">
35673 * @class Roo.tree.DefaultSelectionModel
35674 * @extends Roo.util.Observable
35675 * The default single selection for a TreePanel.
35676 * @param {Object} cfg Configuration
35678 Roo.tree.DefaultSelectionModel = function(cfg){
35679 this.selNode = null;
35685 * @event selectionchange
35686 * Fires when the selected node changes
35687 * @param {DefaultSelectionModel} this
35688 * @param {TreeNode} node the new selection
35690 "selectionchange" : true,
35693 * @event beforeselect
35694 * Fires before the selected node changes, return false to cancel the change
35695 * @param {DefaultSelectionModel} this
35696 * @param {TreeNode} node the new selection
35697 * @param {TreeNode} node the old selection
35699 "beforeselect" : true
35702 Roo.tree.DefaultSelectionModel.superclass.constructor.call(this,cfg);
35705 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
35706 init : function(tree){
35708 tree.getTreeEl().on("keydown", this.onKeyDown, this);
35709 tree.on("click", this.onNodeClick, this);
35712 onNodeClick : function(node, e){
35713 if (e.ctrlKey && this.selNode == node) {
35714 this.unselect(node);
35722 * @param {TreeNode} node The node to select
35723 * @return {TreeNode} The selected node
35725 select : function(node){
35726 var last = this.selNode;
35727 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
35729 last.ui.onSelectedChange(false);
35731 this.selNode = node;
35732 node.ui.onSelectedChange(true);
35733 this.fireEvent("selectionchange", this, node, last);
35740 * @param {TreeNode} node The node to unselect
35742 unselect : function(node){
35743 if(this.selNode == node){
35744 this.clearSelections();
35749 * Clear all selections
35751 clearSelections : function(){
35752 var n = this.selNode;
35754 n.ui.onSelectedChange(false);
35755 this.selNode = null;
35756 this.fireEvent("selectionchange", this, null);
35762 * Get the selected node
35763 * @return {TreeNode} The selected node
35765 getSelectedNode : function(){
35766 return this.selNode;
35770 * Returns true if the node is selected
35771 * @param {TreeNode} node The node to check
35772 * @return {Boolean}
35774 isSelected : function(node){
35775 return this.selNode == node;
35779 * Selects the node above the selected node in the tree, intelligently walking the nodes
35780 * @return TreeNode The new selection
35782 selectPrevious : function(){
35783 var s = this.selNode || this.lastSelNode;
35787 var ps = s.previousSibling;
35789 if(!ps.isExpanded() || ps.childNodes.length < 1){
35790 return this.select(ps);
35792 var lc = ps.lastChild;
35793 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
35796 return this.select(lc);
35798 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
35799 return this.select(s.parentNode);
35805 * Selects the node above the selected node in the tree, intelligently walking the nodes
35806 * @return TreeNode The new selection
35808 selectNext : function(){
35809 var s = this.selNode || this.lastSelNode;
35813 if(s.firstChild && s.isExpanded()){
35814 return this.select(s.firstChild);
35815 }else if(s.nextSibling){
35816 return this.select(s.nextSibling);
35817 }else if(s.parentNode){
35819 s.parentNode.bubble(function(){
35820 if(this.nextSibling){
35821 newS = this.getOwnerTree().selModel.select(this.nextSibling);
35830 onKeyDown : function(e){
35831 var s = this.selNode || this.lastSelNode;
35832 // undesirable, but required
35837 var k = e.getKey();
35845 this.selectPrevious();
35848 e.preventDefault();
35849 if(s.hasChildNodes()){
35850 if(!s.isExpanded()){
35852 }else if(s.firstChild){
35853 this.select(s.firstChild, e);
35858 e.preventDefault();
35859 if(s.hasChildNodes() && s.isExpanded()){
35861 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
35862 this.select(s.parentNode, e);
35870 * @class Roo.tree.MultiSelectionModel
35871 * @extends Roo.util.Observable
35872 * Multi selection for a TreePanel.
35873 * @param {Object} cfg Configuration
35875 Roo.tree.MultiSelectionModel = function(){
35876 this.selNodes = [];
35880 * @event selectionchange
35881 * Fires when the selected nodes change
35882 * @param {MultiSelectionModel} this
35883 * @param {Array} nodes Array of the selected nodes
35885 "selectionchange" : true
35887 Roo.tree.MultiSelectionModel.superclass.constructor.call(this,cfg);
35891 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
35892 init : function(tree){
35894 tree.getTreeEl().on("keydown", this.onKeyDown, this);
35895 tree.on("click", this.onNodeClick, this);
35898 onNodeClick : function(node, e){
35899 this.select(node, e, e.ctrlKey);
35904 * @param {TreeNode} node The node to select
35905 * @param {EventObject} e (optional) An event associated with the selection
35906 * @param {Boolean} keepExisting True to retain existing selections
35907 * @return {TreeNode} The selected node
35909 select : function(node, e, keepExisting){
35910 if(keepExisting !== true){
35911 this.clearSelections(true);
35913 if(this.isSelected(node)){
35914 this.lastSelNode = node;
35917 this.selNodes.push(node);
35918 this.selMap[node.id] = node;
35919 this.lastSelNode = node;
35920 node.ui.onSelectedChange(true);
35921 this.fireEvent("selectionchange", this, this.selNodes);
35927 * @param {TreeNode} node The node to unselect
35929 unselect : function(node){
35930 if(this.selMap[node.id]){
35931 node.ui.onSelectedChange(false);
35932 var sn = this.selNodes;
35935 index = sn.indexOf(node);
35937 for(var i = 0, len = sn.length; i < len; i++){
35945 this.selNodes.splice(index, 1);
35947 delete this.selMap[node.id];
35948 this.fireEvent("selectionchange", this, this.selNodes);
35953 * Clear all selections
35955 clearSelections : function(suppressEvent){
35956 var sn = this.selNodes;
35958 for(var i = 0, len = sn.length; i < len; i++){
35959 sn[i].ui.onSelectedChange(false);
35961 this.selNodes = [];
35963 if(suppressEvent !== true){
35964 this.fireEvent("selectionchange", this, this.selNodes);
35970 * Returns true if the node is selected
35971 * @param {TreeNode} node The node to check
35972 * @return {Boolean}
35974 isSelected : function(node){
35975 return this.selMap[node.id] ? true : false;
35979 * Returns an array of the selected nodes
35982 getSelectedNodes : function(){
35983 return this.selNodes;
35986 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
35988 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
35990 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
35993 * Ext JS Library 1.1.1
35994 * Copyright(c) 2006-2007, Ext JS, LLC.
35996 * Originally Released Under LGPL - original licence link has changed is not relivant.
35999 * <script type="text/javascript">
36003 * @class Roo.tree.TreeNode
36004 * @extends Roo.data.Node
36005 * @cfg {String} text The text for this node
36006 * @cfg {Boolean} expanded true to start the node expanded
36007 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
36008 * @cfg {Boolean} allowDrop false if this node cannot be drop on
36009 * @cfg {Boolean} disabled true to start the node disabled
36010 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
36011 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
36012 * @cfg {String} cls A css class to be added to the node
36013 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
36014 * @cfg {String} href URL of the link used for the node (defaults to #)
36015 * @cfg {String} hrefTarget target frame for the link
36016 * @cfg {String} qtip An Ext QuickTip for the node
36017 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
36018 * @cfg {Boolean} singleClickExpand True for single click expand on this node
36019 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
36020 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
36021 * (defaults to undefined with no checkbox rendered)
36023 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
36025 Roo.tree.TreeNode = function(attributes){
36026 attributes = attributes || {};
36027 if(typeof attributes == "string"){
36028 attributes = {text: attributes};
36030 this.childrenRendered = false;
36031 this.rendered = false;
36032 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
36033 this.expanded = attributes.expanded === true;
36034 this.isTarget = attributes.isTarget !== false;
36035 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
36036 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
36039 * Read-only. The text for this node. To change it use setText().
36042 this.text = attributes.text;
36044 * True if this node is disabled.
36047 this.disabled = attributes.disabled === true;
36051 * @event textchange
36052 * Fires when the text for this node is changed
36053 * @param {Node} this This node
36054 * @param {String} text The new text
36055 * @param {String} oldText The old text
36057 "textchange" : true,
36059 * @event beforeexpand
36060 * Fires before this node is expanded, return false to cancel.
36061 * @param {Node} this This node
36062 * @param {Boolean} deep
36063 * @param {Boolean} anim
36065 "beforeexpand" : true,
36067 * @event beforecollapse
36068 * Fires before this node is collapsed, return false to cancel.
36069 * @param {Node} this This node
36070 * @param {Boolean} deep
36071 * @param {Boolean} anim
36073 "beforecollapse" : true,
36076 * Fires when this node is expanded
36077 * @param {Node} this This node
36081 * @event disabledchange
36082 * Fires when the disabled status of this node changes
36083 * @param {Node} this This node
36084 * @param {Boolean} disabled
36086 "disabledchange" : true,
36089 * Fires when this node is collapsed
36090 * @param {Node} this This node
36094 * @event beforeclick
36095 * Fires before click processing. Return false to cancel the default action.
36096 * @param {Node} this This node
36097 * @param {Roo.EventObject} e The event object
36099 "beforeclick":true,
36101 * @event checkchange
36102 * Fires when a node with a checkbox's checked property changes
36103 * @param {Node} this This node
36104 * @param {Boolean} checked
36106 "checkchange":true,
36109 * Fires when this node is clicked
36110 * @param {Node} this This node
36111 * @param {Roo.EventObject} e The event object
36116 * Fires when this node is double clicked
36117 * @param {Node} this This node
36118 * @param {Roo.EventObject} e The event object
36122 * @event contextmenu
36123 * Fires when this node is right clicked
36124 * @param {Node} this This node
36125 * @param {Roo.EventObject} e The event object
36127 "contextmenu":true,
36129 * @event beforechildrenrendered
36130 * Fires right before the child nodes for this node are rendered
36131 * @param {Node} this This node
36133 "beforechildrenrendered":true
36136 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
36139 * Read-only. The UI for this node
36142 this.ui = new uiClass(this);
36144 // finally support items[]
36145 if (typeof(this.attributes.items) == 'undefined' || !this.attributes.items) {
36150 Roo.each(this.attributes.items, function(c) {
36151 this.appendChild(Roo.factory(c,Roo.Tree));
36153 delete this.attributes.items;
36158 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
36159 preventHScroll: true,
36161 * Returns true if this node is expanded
36162 * @return {Boolean}
36164 isExpanded : function(){
36165 return this.expanded;
36169 * Returns the UI object for this node
36170 * @return {TreeNodeUI}
36172 getUI : function(){
36176 // private override
36177 setFirstChild : function(node){
36178 var of = this.firstChild;
36179 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
36180 if(this.childrenRendered && of && node != of){
36181 of.renderIndent(true, true);
36184 this.renderIndent(true, true);
36188 // private override
36189 setLastChild : function(node){
36190 var ol = this.lastChild;
36191 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
36192 if(this.childrenRendered && ol && node != ol){
36193 ol.renderIndent(true, true);
36196 this.renderIndent(true, true);
36200 // these methods are overridden to provide lazy rendering support
36201 // private override
36202 appendChild : function()
36204 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
36205 if(node && this.childrenRendered){
36208 this.ui.updateExpandIcon();
36212 // private override
36213 removeChild : function(node){
36214 this.ownerTree.getSelectionModel().unselect(node);
36215 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
36216 // if it's been rendered remove dom node
36217 if(this.childrenRendered){
36220 if(this.childNodes.length < 1){
36221 this.collapse(false, false);
36223 this.ui.updateExpandIcon();
36225 if(!this.firstChild) {
36226 this.childrenRendered = false;
36231 // private override
36232 insertBefore : function(node, refNode){
36233 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
36234 if(newNode && refNode && this.childrenRendered){
36237 this.ui.updateExpandIcon();
36242 * Sets the text for this node
36243 * @param {String} text
36245 setText : function(text){
36246 var oldText = this.text;
36248 this.attributes.text = text;
36249 if(this.rendered){ // event without subscribing
36250 this.ui.onTextChange(this, text, oldText);
36252 this.fireEvent("textchange", this, text, oldText);
36256 * Triggers selection of this node
36258 select : function(){
36259 this.getOwnerTree().getSelectionModel().select(this);
36263 * Triggers deselection of this node
36265 unselect : function(){
36266 this.getOwnerTree().getSelectionModel().unselect(this);
36270 * Returns true if this node is selected
36271 * @return {Boolean}
36273 isSelected : function(){
36274 return this.getOwnerTree().getSelectionModel().isSelected(this);
36278 * Expand this node.
36279 * @param {Boolean} deep (optional) True to expand all children as well
36280 * @param {Boolean} anim (optional) false to cancel the default animation
36281 * @param {Function} callback (optional) A callback to be called when
36282 * expanding this node completes (does not wait for deep expand to complete).
36283 * Called with 1 parameter, this node.
36285 expand : function(deep, anim, callback){
36286 if(!this.expanded){
36287 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
36290 if(!this.childrenRendered){
36291 this.renderChildren();
36293 this.expanded = true;
36295 if(!this.isHiddenRoot() && (this.getOwnerTree() && this.getOwnerTree().animate && anim !== false) || anim){
36296 this.ui.animExpand(function(){
36297 this.fireEvent("expand", this);
36298 if(typeof callback == "function"){
36302 this.expandChildNodes(true);
36304 }.createDelegate(this));
36308 this.fireEvent("expand", this);
36309 if(typeof callback == "function"){
36314 if(typeof callback == "function"){
36319 this.expandChildNodes(true);
36323 isHiddenRoot : function(){
36324 return this.isRoot && !this.getOwnerTree().rootVisible;
36328 * Collapse this node.
36329 * @param {Boolean} deep (optional) True to collapse all children as well
36330 * @param {Boolean} anim (optional) false to cancel the default animation
36332 collapse : function(deep, anim){
36333 if(this.expanded && !this.isHiddenRoot()){
36334 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
36337 this.expanded = false;
36338 if((this.getOwnerTree().animate && anim !== false) || anim){
36339 this.ui.animCollapse(function(){
36340 this.fireEvent("collapse", this);
36342 this.collapseChildNodes(true);
36344 }.createDelegate(this));
36347 this.ui.collapse();
36348 this.fireEvent("collapse", this);
36352 var cs = this.childNodes;
36353 for(var i = 0, len = cs.length; i < len; i++) {
36354 cs[i].collapse(true, false);
36360 delayedExpand : function(delay){
36361 if(!this.expandProcId){
36362 this.expandProcId = this.expand.defer(delay, this);
36367 cancelExpand : function(){
36368 if(this.expandProcId){
36369 clearTimeout(this.expandProcId);
36371 this.expandProcId = false;
36375 * Toggles expanded/collapsed state of the node
36377 toggle : function(){
36386 * Ensures all parent nodes are expanded
36388 ensureVisible : function(callback){
36389 var tree = this.getOwnerTree();
36390 tree.expandPath(this.parentNode.getPath(), false, function(){
36391 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
36392 Roo.callback(callback);
36393 }.createDelegate(this));
36397 * Expand all child nodes
36398 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
36400 expandChildNodes : function(deep){
36401 var cs = this.childNodes;
36402 for(var i = 0, len = cs.length; i < len; i++) {
36403 cs[i].expand(deep);
36408 * Collapse all child nodes
36409 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
36411 collapseChildNodes : function(deep){
36412 var cs = this.childNodes;
36413 for(var i = 0, len = cs.length; i < len; i++) {
36414 cs[i].collapse(deep);
36419 * Disables this node
36421 disable : function(){
36422 this.disabled = true;
36424 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
36425 this.ui.onDisableChange(this, true);
36427 this.fireEvent("disabledchange", this, true);
36431 * Enables this node
36433 enable : function(){
36434 this.disabled = false;
36435 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
36436 this.ui.onDisableChange(this, false);
36438 this.fireEvent("disabledchange", this, false);
36442 renderChildren : function(suppressEvent){
36443 if(suppressEvent !== false){
36444 this.fireEvent("beforechildrenrendered", this);
36446 var cs = this.childNodes;
36447 for(var i = 0, len = cs.length; i < len; i++){
36448 cs[i].render(true);
36450 this.childrenRendered = true;
36454 sort : function(fn, scope){
36455 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
36456 if(this.childrenRendered){
36457 var cs = this.childNodes;
36458 for(var i = 0, len = cs.length; i < len; i++){
36459 cs[i].render(true);
36465 render : function(bulkRender){
36466 this.ui.render(bulkRender);
36467 if(!this.rendered){
36468 this.rendered = true;
36470 this.expanded = false;
36471 this.expand(false, false);
36477 renderIndent : function(deep, refresh){
36479 this.ui.childIndent = null;
36481 this.ui.renderIndent();
36482 if(deep === true && this.childrenRendered){
36483 var cs = this.childNodes;
36484 for(var i = 0, len = cs.length; i < len; i++){
36485 cs[i].renderIndent(true, refresh);
36491 * Ext JS Library 1.1.1
36492 * Copyright(c) 2006-2007, Ext JS, LLC.
36494 * Originally Released Under LGPL - original licence link has changed is not relivant.
36497 * <script type="text/javascript">
36501 * @class Roo.tree.AsyncTreeNode
36502 * @extends Roo.tree.TreeNode
36503 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
36505 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
36507 Roo.tree.AsyncTreeNode = function(config){
36508 this.loaded = false;
36509 this.loading = false;
36510 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
36512 * @event beforeload
36513 * Fires before this node is loaded, return false to cancel
36514 * @param {Node} this This node
36516 this.addEvents({'beforeload':true, 'load': true});
36519 * Fires when this node is loaded
36520 * @param {Node} this This node
36523 * The loader used by this node (defaults to using the tree's defined loader)
36528 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
36529 expand : function(deep, anim, callback){
36530 if(this.loading){ // if an async load is already running, waiting til it's done
36532 var f = function(){
36533 if(!this.loading){ // done loading
36534 clearInterval(timer);
36535 this.expand(deep, anim, callback);
36537 }.createDelegate(this);
36538 timer = setInterval(f, 200);
36542 if(this.fireEvent("beforeload", this) === false){
36545 this.loading = true;
36546 this.ui.beforeLoad(this);
36547 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
36549 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
36553 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
36557 * Returns true if this node is currently loading
36558 * @return {Boolean}
36560 isLoading : function(){
36561 return this.loading;
36564 loadComplete : function(deep, anim, callback){
36565 this.loading = false;
36566 this.loaded = true;
36567 this.ui.afterLoad(this);
36568 this.fireEvent("load", this);
36569 this.expand(deep, anim, callback);
36573 * Returns true if this node has been loaded
36574 * @return {Boolean}
36576 isLoaded : function(){
36577 return this.loaded;
36580 hasChildNodes : function(){
36581 if(!this.isLeaf() && !this.loaded){
36584 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
36589 * Trigger a reload for this node
36590 * @param {Function} callback
36592 reload : function(callback){
36593 this.collapse(false, false);
36594 while(this.firstChild){
36595 this.removeChild(this.firstChild);
36597 this.childrenRendered = false;
36598 this.loaded = false;
36599 if(this.isHiddenRoot()){
36600 this.expanded = false;
36602 this.expand(false, false, callback);
36606 * Ext JS Library 1.1.1
36607 * Copyright(c) 2006-2007, Ext JS, LLC.
36609 * Originally Released Under LGPL - original licence link has changed is not relivant.
36612 * <script type="text/javascript">
36616 * @class Roo.tree.TreeNodeUI
36618 * @param {Object} node The node to render
36619 * The TreeNode UI implementation is separate from the
36620 * tree implementation. Unless you are customizing the tree UI,
36621 * you should never have to use this directly.
36623 Roo.tree.TreeNodeUI = function(node){
36625 this.rendered = false;
36626 this.animating = false;
36627 this.emptyIcon = Roo.BLANK_IMAGE_URL;
36630 Roo.tree.TreeNodeUI.prototype = {
36631 removeChild : function(node){
36633 this.ctNode.removeChild(node.ui.getEl());
36637 beforeLoad : function(){
36638 this.addClass("x-tree-node-loading");
36641 afterLoad : function(){
36642 this.removeClass("x-tree-node-loading");
36645 onTextChange : function(node, text, oldText){
36647 this.textNode.innerHTML = text;
36651 onDisableChange : function(node, state){
36652 this.disabled = state;
36654 this.addClass("x-tree-node-disabled");
36656 this.removeClass("x-tree-node-disabled");
36660 onSelectedChange : function(state){
36663 this.addClass("x-tree-selected");
36666 this.removeClass("x-tree-selected");
36670 onMove : function(tree, node, oldParent, newParent, index, refNode){
36671 this.childIndent = null;
36673 var targetNode = newParent.ui.getContainer();
36674 if(!targetNode){//target not rendered
36675 this.holder = document.createElement("div");
36676 this.holder.appendChild(this.wrap);
36679 var insertBefore = refNode ? refNode.ui.getEl() : null;
36681 targetNode.insertBefore(this.wrap, insertBefore);
36683 targetNode.appendChild(this.wrap);
36685 this.node.renderIndent(true);
36689 addClass : function(cls){
36691 Roo.fly(this.elNode).addClass(cls);
36695 removeClass : function(cls){
36697 Roo.fly(this.elNode).removeClass(cls);
36701 remove : function(){
36703 this.holder = document.createElement("div");
36704 this.holder.appendChild(this.wrap);
36708 fireEvent : function(){
36709 return this.node.fireEvent.apply(this.node, arguments);
36712 initEvents : function(){
36713 this.node.on("move", this.onMove, this);
36714 var E = Roo.EventManager;
36715 var a = this.anchor;
36717 var el = Roo.fly(a, '_treeui');
36719 if(Roo.isOpera){ // opera render bug ignores the CSS
36720 el.setStyle("text-decoration", "none");
36723 el.on("click", this.onClick, this);
36724 el.on("dblclick", this.onDblClick, this);
36727 Roo.EventManager.on(this.checkbox,
36728 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
36731 el.on("contextmenu", this.onContextMenu, this);
36733 var icon = Roo.fly(this.iconNode);
36734 icon.on("click", this.onClick, this);
36735 icon.on("dblclick", this.onDblClick, this);
36736 icon.on("contextmenu", this.onContextMenu, this);
36737 E.on(this.ecNode, "click", this.ecClick, this, true);
36739 if(this.node.disabled){
36740 this.addClass("x-tree-node-disabled");
36742 if(this.node.hidden){
36743 this.addClass("x-tree-node-disabled");
36745 var ot = this.node.getOwnerTree();
36746 var dd = ot ? (ot.enableDD || ot.enableDrag || ot.enableDrop) : false;
36747 if(dd && (!this.node.isRoot || ot.rootVisible)){
36748 Roo.dd.Registry.register(this.elNode, {
36750 handles: this.getDDHandles(),
36756 getDDHandles : function(){
36757 return [this.iconNode, this.textNode];
36762 this.wrap.style.display = "none";
36768 this.wrap.style.display = "";
36772 onContextMenu : function(e){
36773 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
36774 e.preventDefault();
36776 this.fireEvent("contextmenu", this.node, e);
36780 onClick : function(e){
36785 if(this.fireEvent("beforeclick", this.node, e) !== false){
36786 if(!this.disabled && this.node.attributes.href){
36787 this.fireEvent("click", this.node, e);
36790 e.preventDefault();
36795 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
36796 this.node.toggle();
36799 this.fireEvent("click", this.node, e);
36805 onDblClick : function(e){
36806 e.preventDefault();
36811 this.toggleCheck();
36813 if(!this.animating && this.node.hasChildNodes()){
36814 this.node.toggle();
36816 this.fireEvent("dblclick", this.node, e);
36819 onCheckChange : function(){
36820 var checked = this.checkbox.checked;
36821 this.node.attributes.checked = checked;
36822 this.fireEvent('checkchange', this.node, checked);
36825 ecClick : function(e){
36826 if(!this.animating && this.node.hasChildNodes()){
36827 this.node.toggle();
36831 startDrop : function(){
36832 this.dropping = true;
36835 // delayed drop so the click event doesn't get fired on a drop
36836 endDrop : function(){
36837 setTimeout(function(){
36838 this.dropping = false;
36839 }.createDelegate(this), 50);
36842 expand : function(){
36843 this.updateExpandIcon();
36844 this.ctNode.style.display = "";
36847 focus : function(){
36848 if(!this.node.preventHScroll){
36849 try{this.anchor.focus();
36851 }else if(!Roo.isIE){
36853 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
36854 var l = noscroll.scrollLeft;
36855 this.anchor.focus();
36856 noscroll.scrollLeft = l;
36861 toggleCheck : function(value){
36862 var cb = this.checkbox;
36864 cb.checked = (value === undefined ? !cb.checked : value);
36870 this.anchor.blur();
36874 animExpand : function(callback){
36875 var ct = Roo.get(this.ctNode);
36877 if(!this.node.hasChildNodes()){
36878 this.updateExpandIcon();
36879 this.ctNode.style.display = "";
36880 Roo.callback(callback);
36883 this.animating = true;
36884 this.updateExpandIcon();
36887 callback : function(){
36888 this.animating = false;
36889 Roo.callback(callback);
36892 duration: this.node.ownerTree.duration || .25
36896 highlight : function(){
36897 var tree = this.node.getOwnerTree();
36898 Roo.fly(this.wrap).highlight(
36899 tree.hlColor || "C3DAF9",
36900 {endColor: tree.hlBaseColor}
36904 collapse : function(){
36905 this.updateExpandIcon();
36906 this.ctNode.style.display = "none";
36909 animCollapse : function(callback){
36910 var ct = Roo.get(this.ctNode);
36911 ct.enableDisplayMode('block');
36914 this.animating = true;
36915 this.updateExpandIcon();
36918 callback : function(){
36919 this.animating = false;
36920 Roo.callback(callback);
36923 duration: this.node.ownerTree.duration || .25
36927 getContainer : function(){
36928 return this.ctNode;
36931 getEl : function(){
36935 appendDDGhost : function(ghostNode){
36936 ghostNode.appendChild(this.elNode.cloneNode(true));
36939 getDDRepairXY : function(){
36940 return Roo.lib.Dom.getXY(this.iconNode);
36943 onRender : function(){
36947 render : function(bulkRender){
36948 var n = this.node, a = n.attributes;
36949 var targetNode = n.parentNode ?
36950 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
36952 if(!this.rendered){
36953 this.rendered = true;
36955 this.renderElements(n, a, targetNode, bulkRender);
36958 if(this.textNode.setAttributeNS){
36959 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
36961 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
36964 this.textNode.setAttribute("ext:qtip", a.qtip);
36966 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
36969 }else if(a.qtipCfg){
36970 a.qtipCfg.target = Roo.id(this.textNode);
36971 Roo.QuickTips.register(a.qtipCfg);
36974 if(!this.node.expanded){
36975 this.updateExpandIcon();
36978 if(bulkRender === true) {
36979 targetNode.appendChild(this.wrap);
36984 renderElements : function(n, a, targetNode, bulkRender)
36986 // add some indent caching, this helps performance when rendering a large tree
36987 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
36988 var t = n.getOwnerTree();
36989 var txt = t && t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
36990 if (typeof(n.attributes.html) != 'undefined') {
36991 txt = n.attributes.html;
36993 var tip = t && t.rendererTip ? t.rendererTip(n.attributes) : txt;
36994 var cb = typeof a.checked == 'boolean';
36995 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
36996 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
36997 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
36998 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
36999 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
37000 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
37001 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
37002 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
37003 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
37004 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
37007 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
37008 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
37009 n.nextSibling.ui.getEl(), buf.join(""));
37011 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
37014 this.elNode = this.wrap.childNodes[0];
37015 this.ctNode = this.wrap.childNodes[1];
37016 var cs = this.elNode.childNodes;
37017 this.indentNode = cs[0];
37018 this.ecNode = cs[1];
37019 this.iconNode = cs[2];
37022 this.checkbox = cs[3];
37025 this.anchor = cs[index];
37026 this.textNode = cs[index].firstChild;
37029 getAnchor : function(){
37030 return this.anchor;
37033 getTextEl : function(){
37034 return this.textNode;
37037 getIconEl : function(){
37038 return this.iconNode;
37041 isChecked : function(){
37042 return this.checkbox ? this.checkbox.checked : false;
37045 updateExpandIcon : function(){
37047 var n = this.node, c1, c2;
37048 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
37049 var hasChild = n.hasChildNodes();
37053 c1 = "x-tree-node-collapsed";
37054 c2 = "x-tree-node-expanded";
37057 c1 = "x-tree-node-expanded";
37058 c2 = "x-tree-node-collapsed";
37061 this.removeClass("x-tree-node-leaf");
37062 this.wasLeaf = false;
37064 if(this.c1 != c1 || this.c2 != c2){
37065 Roo.fly(this.elNode).replaceClass(c1, c2);
37066 this.c1 = c1; this.c2 = c2;
37069 // this changes non-leafs into leafs if they have no children.
37070 // it's not very rational behaviour..
37072 if(!this.wasLeaf && this.node.leaf){
37073 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
37076 this.wasLeaf = true;
37079 var ecc = "x-tree-ec-icon "+cls;
37080 if(this.ecc != ecc){
37081 this.ecNode.className = ecc;
37087 getChildIndent : function(){
37088 if(!this.childIndent){
37092 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
37094 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
37096 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
37101 this.childIndent = buf.join("");
37103 return this.childIndent;
37106 renderIndent : function(){
37109 var p = this.node.parentNode;
37111 indent = p.ui.getChildIndent();
37113 if(this.indentMarkup != indent){ // don't rerender if not required
37114 this.indentNode.innerHTML = indent;
37115 this.indentMarkup = indent;
37117 this.updateExpandIcon();
37122 Roo.tree.RootTreeNodeUI = function(){
37123 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
37125 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
37126 render : function(){
37127 if(!this.rendered){
37128 var targetNode = this.node.ownerTree.innerCt.dom;
37129 this.node.expanded = true;
37130 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
37131 this.wrap = this.ctNode = targetNode.firstChild;
37134 collapse : function(){
37136 expand : function(){
37140 * Ext JS Library 1.1.1
37141 * Copyright(c) 2006-2007, Ext JS, LLC.
37143 * Originally Released Under LGPL - original licence link has changed is not relivant.
37146 * <script type="text/javascript">
37149 * @class Roo.tree.TreeLoader
37150 * @extends Roo.util.Observable
37151 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
37152 * nodes from a specified URL. The response must be a javascript Array definition
37153 * who's elements are node definition objects. eg:
37158 { 'id': 1, 'text': 'A folder Node', 'leaf': false },
37159 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }
37166 * The old style respose with just an array is still supported, but not recommended.
37169 * A server request is sent, and child nodes are loaded only when a node is expanded.
37170 * The loading node's id is passed to the server under the parameter name "node" to
37171 * enable the server to produce the correct child nodes.
37173 * To pass extra parameters, an event handler may be attached to the "beforeload"
37174 * event, and the parameters specified in the TreeLoader's baseParams property:
37176 myTreeLoader.on("beforeload", function(treeLoader, node) {
37177 this.baseParams.category = node.attributes.category;
37182 * This would pass an HTTP parameter called "category" to the server containing
37183 * the value of the Node's "category" attribute.
37185 * Creates a new Treeloader.
37186 * @param {Object} config A config object containing config properties.
37188 Roo.tree.TreeLoader = function(config){
37189 this.baseParams = {};
37190 this.requestMethod = "POST";
37191 Roo.apply(this, config);
37196 * @event beforeload
37197 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
37198 * @param {Object} This TreeLoader object.
37199 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
37200 * @param {Object} callback The callback function specified in the {@link #load} call.
37205 * Fires when the node has been successfuly loaded.
37206 * @param {Object} This TreeLoader object.
37207 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
37208 * @param {Object} response The response object containing the data from the server.
37212 * @event loadexception
37213 * Fires if the network request failed.
37214 * @param {Object} This TreeLoader object.
37215 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
37216 * @param {Object} response The response object containing the data from the server.
37218 loadexception : true,
37221 * Fires before a node is created, enabling you to return custom Node types
37222 * @param {Object} This TreeLoader object.
37223 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
37228 Roo.tree.TreeLoader.superclass.constructor.call(this);
37231 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
37233 * @cfg {String} dataUrl The URL from which to request a Json string which
37234 * specifies an array of node definition object representing the child nodes
37238 * @cfg {String} requestMethod either GET or POST
37239 * defaults to POST (due to BC)
37243 * @cfg {Object} baseParams (optional) An object containing properties which
37244 * specify HTTP parameters to be passed to each request for child nodes.
37247 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
37248 * created by this loader. If the attributes sent by the server have an attribute in this object,
37249 * they take priority.
37252 * @cfg {Object} uiProviders (optional) An object containing properties which
37254 * DEPRECATED - use 'create' event handler to modify attributes - which affect creation.
37255 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
37256 * <i>uiProvider</i> attribute of a returned child node is a string rather
37257 * than a reference to a TreeNodeUI implementation, this that string value
37258 * is used as a property name in the uiProviders object. You can define the provider named
37259 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
37264 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
37265 * child nodes before loading.
37267 clearOnLoad : true,
37270 * @cfg {String} root (optional) Default to false. Use this to read data from an object
37271 * property on loading, rather than expecting an array. (eg. more compatible to a standard
37272 * Grid query { data : [ .....] }
37277 * @cfg {String} queryParam (optional)
37278 * Name of the query as it will be passed on the querystring (defaults to 'node')
37279 * eg. the request will be ?node=[id]
37286 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
37287 * This is called automatically when a node is expanded, but may be used to reload
37288 * a node (or append new children if the {@link #clearOnLoad} option is false.)
37289 * @param {Roo.tree.TreeNode} node
37290 * @param {Function} callback
37292 load : function(node, callback){
37293 if(this.clearOnLoad){
37294 while(node.firstChild){
37295 node.removeChild(node.firstChild);
37298 if(node.attributes.children){ // preloaded json children
37299 var cs = node.attributes.children;
37300 for(var i = 0, len = cs.length; i < len; i++){
37301 node.appendChild(this.createNode(cs[i]));
37303 if(typeof callback == "function"){
37306 }else if(this.dataUrl){
37307 this.requestData(node, callback);
37311 getParams: function(node){
37312 var buf = [], bp = this.baseParams;
37313 for(var key in bp){
37314 if(typeof bp[key] != "function"){
37315 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
37318 var n = this.queryParam === false ? 'node' : this.queryParam;
37319 buf.push(n + "=", encodeURIComponent(node.id));
37320 return buf.join("");
37323 requestData : function(node, callback){
37324 if(this.fireEvent("beforeload", this, node, callback) !== false){
37325 this.transId = Roo.Ajax.request({
37326 method:this.requestMethod,
37327 url: this.dataUrl||this.url,
37328 success: this.handleResponse,
37329 failure: this.handleFailure,
37331 argument: {callback: callback, node: node},
37332 params: this.getParams(node)
37335 // if the load is cancelled, make sure we notify
37336 // the node that we are done
37337 if(typeof callback == "function"){
37343 isLoading : function(){
37344 return this.transId ? true : false;
37347 abort : function(){
37348 if(this.isLoading()){
37349 Roo.Ajax.abort(this.transId);
37354 createNode : function(attr)
37356 // apply baseAttrs, nice idea Corey!
37357 if(this.baseAttrs){
37358 Roo.applyIf(attr, this.baseAttrs);
37360 if(this.applyLoader !== false){
37361 attr.loader = this;
37363 // uiProvider = depreciated..
37365 if(typeof(attr.uiProvider) == 'string'){
37366 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
37367 /** eval:var:attr */ eval(attr.uiProvider);
37369 if(typeof(this.uiProviders['default']) != 'undefined') {
37370 attr.uiProvider = this.uiProviders['default'];
37373 this.fireEvent('create', this, attr);
37375 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
37377 new Roo.tree.TreeNode(attr) :
37378 new Roo.tree.AsyncTreeNode(attr));
37381 processResponse : function(response, node, callback)
37383 var json = response.responseText;
37386 var o = Roo.decode(json);
37388 if (this.root === false && typeof(o.success) != undefined) {
37389 this.root = 'data'; // the default behaviour for list like data..
37392 if (this.root !== false && !o.success) {
37393 // it's a failure condition.
37394 var a = response.argument;
37395 this.fireEvent("loadexception", this, a.node, response);
37396 Roo.log("Load failed - should have a handler really");
37402 if (this.root !== false) {
37406 for(var i = 0, len = o.length; i < len; i++){
37407 var n = this.createNode(o[i]);
37409 node.appendChild(n);
37412 if(typeof callback == "function"){
37413 callback(this, node);
37416 this.handleFailure(response);
37420 handleResponse : function(response){
37421 this.transId = false;
37422 var a = response.argument;
37423 this.processResponse(response, a.node, a.callback);
37424 this.fireEvent("load", this, a.node, response);
37427 handleFailure : function(response)
37429 // should handle failure better..
37430 this.transId = false;
37431 var a = response.argument;
37432 this.fireEvent("loadexception", this, a.node, response);
37433 if(typeof a.callback == "function"){
37434 a.callback(this, a.node);
37439 * Ext JS Library 1.1.1
37440 * Copyright(c) 2006-2007, Ext JS, LLC.
37442 * Originally Released Under LGPL - original licence link has changed is not relivant.
37445 * <script type="text/javascript">
37449 * @class Roo.tree.TreeFilter
37450 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
37451 * @param {TreePanel} tree
37452 * @param {Object} config (optional)
37454 Roo.tree.TreeFilter = function(tree, config){
37456 this.filtered = {};
37457 Roo.apply(this, config);
37460 Roo.tree.TreeFilter.prototype = {
37467 * Filter the data by a specific attribute.
37468 * @param {String/RegExp} value Either string that the attribute value
37469 * should start with or a RegExp to test against the attribute
37470 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
37471 * @param {TreeNode} startNode (optional) The node to start the filter at.
37473 filter : function(value, attr, startNode){
37474 attr = attr || "text";
37476 if(typeof value == "string"){
37477 var vlen = value.length;
37478 // auto clear empty filter
37479 if(vlen == 0 && this.clearBlank){
37483 value = value.toLowerCase();
37485 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
37487 }else if(value.exec){ // regex?
37489 return value.test(n.attributes[attr]);
37492 throw 'Illegal filter type, must be string or regex';
37494 this.filterBy(f, null, startNode);
37498 * Filter by a function. The passed function will be called with each
37499 * node in the tree (or from the startNode). If the function returns true, the node is kept
37500 * otherwise it is filtered. If a node is filtered, its children are also filtered.
37501 * @param {Function} fn The filter function
37502 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
37504 filterBy : function(fn, scope, startNode){
37505 startNode = startNode || this.tree.root;
37506 if(this.autoClear){
37509 var af = this.filtered, rv = this.reverse;
37510 var f = function(n){
37511 if(n == startNode){
37517 var m = fn.call(scope || n, n);
37525 startNode.cascade(f);
37528 if(typeof id != "function"){
37530 if(n && n.parentNode){
37531 n.parentNode.removeChild(n);
37539 * Clears the current filter. Note: with the "remove" option
37540 * set a filter cannot be cleared.
37542 clear : function(){
37544 var af = this.filtered;
37546 if(typeof id != "function"){
37553 this.filtered = {};
37558 * Ext JS Library 1.1.1
37559 * Copyright(c) 2006-2007, Ext JS, LLC.
37561 * Originally Released Under LGPL - original licence link has changed is not relivant.
37564 * <script type="text/javascript">
37569 * @class Roo.tree.TreeSorter
37570 * Provides sorting of nodes in a TreePanel
37572 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
37573 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
37574 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
37575 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
37576 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
37577 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
37579 * @param {TreePanel} tree
37580 * @param {Object} config
37582 Roo.tree.TreeSorter = function(tree, config){
37583 Roo.apply(this, config);
37584 tree.on("beforechildrenrendered", this.doSort, this);
37585 tree.on("append", this.updateSort, this);
37586 tree.on("insert", this.updateSort, this);
37588 var dsc = this.dir && this.dir.toLowerCase() == "desc";
37589 var p = this.property || "text";
37590 var sortType = this.sortType;
37591 var fs = this.folderSort;
37592 var cs = this.caseSensitive === true;
37593 var leafAttr = this.leafAttr || 'leaf';
37595 this.sortFn = function(n1, n2){
37597 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
37600 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
37604 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
37605 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
37607 return dsc ? +1 : -1;
37609 return dsc ? -1 : +1;
37616 Roo.tree.TreeSorter.prototype = {
37617 doSort : function(node){
37618 node.sort(this.sortFn);
37621 compareNodes : function(n1, n2){
37622 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
37625 updateSort : function(tree, node){
37626 if(node.childrenRendered){
37627 this.doSort.defer(1, this, [node]);
37632 * Ext JS Library 1.1.1
37633 * Copyright(c) 2006-2007, Ext JS, LLC.
37635 * Originally Released Under LGPL - original licence link has changed is not relivant.
37638 * <script type="text/javascript">
37641 if(Roo.dd.DropZone){
37643 Roo.tree.TreeDropZone = function(tree, config){
37644 this.allowParentInsert = false;
37645 this.allowContainerDrop = false;
37646 this.appendOnly = false;
37647 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
37649 this.lastInsertClass = "x-tree-no-status";
37650 this.dragOverData = {};
37653 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
37654 ddGroup : "TreeDD",
37657 expandDelay : 1000,
37659 expandNode : function(node){
37660 if(node.hasChildNodes() && !node.isExpanded()){
37661 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
37665 queueExpand : function(node){
37666 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
37669 cancelExpand : function(){
37670 if(this.expandProcId){
37671 clearTimeout(this.expandProcId);
37672 this.expandProcId = false;
37676 isValidDropPoint : function(n, pt, dd, e, data){
37677 if(!n || !data){ return false; }
37678 var targetNode = n.node;
37679 var dropNode = data.node;
37680 // default drop rules
37681 if(!(targetNode && targetNode.isTarget && pt)){
37684 if(pt == "append" && targetNode.allowChildren === false){
37687 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
37690 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
37693 // reuse the object
37694 var overEvent = this.dragOverData;
37695 overEvent.tree = this.tree;
37696 overEvent.target = targetNode;
37697 overEvent.data = data;
37698 overEvent.point = pt;
37699 overEvent.source = dd;
37700 overEvent.rawEvent = e;
37701 overEvent.dropNode = dropNode;
37702 overEvent.cancel = false;
37703 var result = this.tree.fireEvent("nodedragover", overEvent);
37704 return overEvent.cancel === false && result !== false;
37707 getDropPoint : function(e, n, dd)
37711 return tn.allowChildren !== false ? "append" : false; // always append for root
37713 var dragEl = n.ddel;
37714 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
37715 var y = Roo.lib.Event.getPageY(e);
37716 //var noAppend = tn.allowChildren === false || tn.isLeaf();
37718 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
37719 var noAppend = tn.allowChildren === false;
37720 if(this.appendOnly || tn.parentNode.allowChildren === false){
37721 return noAppend ? false : "append";
37723 var noBelow = false;
37724 if(!this.allowParentInsert){
37725 noBelow = tn.hasChildNodes() && tn.isExpanded();
37727 var q = (b - t) / (noAppend ? 2 : 3);
37728 if(y >= t && y < (t + q)){
37730 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
37737 onNodeEnter : function(n, dd, e, data)
37739 this.cancelExpand();
37742 onNodeOver : function(n, dd, e, data)
37745 var pt = this.getDropPoint(e, n, dd);
37748 // auto node expand check
37749 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
37750 this.queueExpand(node);
37751 }else if(pt != "append"){
37752 this.cancelExpand();
37755 // set the insert point style on the target node
37756 var returnCls = this.dropNotAllowed;
37757 if(this.isValidDropPoint(n, pt, dd, e, data)){
37762 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
37763 cls = "x-tree-drag-insert-above";
37764 }else if(pt == "below"){
37765 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
37766 cls = "x-tree-drag-insert-below";
37768 returnCls = "x-tree-drop-ok-append";
37769 cls = "x-tree-drag-append";
37771 if(this.lastInsertClass != cls){
37772 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
37773 this.lastInsertClass = cls;
37780 onNodeOut : function(n, dd, e, data){
37782 this.cancelExpand();
37783 this.removeDropIndicators(n);
37786 onNodeDrop : function(n, dd, e, data){
37787 var point = this.getDropPoint(e, n, dd);
37788 var targetNode = n.node;
37789 targetNode.ui.startDrop();
37790 if(!this.isValidDropPoint(n, point, dd, e, data)){
37791 targetNode.ui.endDrop();
37794 // first try to find the drop node
37795 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
37798 target: targetNode,
37803 dropNode: dropNode,
37806 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
37807 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
37808 targetNode.ui.endDrop();
37811 // allow target changing
37812 targetNode = dropEvent.target;
37813 if(point == "append" && !targetNode.isExpanded()){
37814 targetNode.expand(false, null, function(){
37815 this.completeDrop(dropEvent);
37816 }.createDelegate(this));
37818 this.completeDrop(dropEvent);
37823 completeDrop : function(de){
37824 var ns = de.dropNode, p = de.point, t = de.target;
37825 if(!(ns instanceof Array)){
37829 for(var i = 0, len = ns.length; i < len; i++){
37832 t.parentNode.insertBefore(n, t);
37833 }else if(p == "below"){
37834 t.parentNode.insertBefore(n, t.nextSibling);
37840 if(this.tree.hlDrop){
37844 this.tree.fireEvent("nodedrop", de);
37847 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
37848 if(this.tree.hlDrop){
37849 dropNode.ui.focus();
37850 dropNode.ui.highlight();
37852 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
37855 getTree : function(){
37859 removeDropIndicators : function(n){
37862 Roo.fly(el).removeClass([
37863 "x-tree-drag-insert-above",
37864 "x-tree-drag-insert-below",
37865 "x-tree-drag-append"]);
37866 this.lastInsertClass = "_noclass";
37870 beforeDragDrop : function(target, e, id){
37871 this.cancelExpand();
37875 afterRepair : function(data){
37876 if(data && Roo.enableFx){
37877 data.node.ui.highlight();
37887 * Ext JS Library 1.1.1
37888 * Copyright(c) 2006-2007, Ext JS, LLC.
37890 * Originally Released Under LGPL - original licence link has changed is not relivant.
37893 * <script type="text/javascript">
37897 if(Roo.dd.DragZone){
37898 Roo.tree.TreeDragZone = function(tree, config){
37899 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
37903 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
37904 ddGroup : "TreeDD",
37906 onBeforeDrag : function(data, e){
37908 return n && n.draggable && !n.disabled;
37912 onInitDrag : function(e){
37913 var data = this.dragData;
37914 this.tree.getSelectionModel().select(data.node);
37915 this.proxy.update("");
37916 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
37917 this.tree.fireEvent("startdrag", this.tree, data.node, e);
37920 getRepairXY : function(e, data){
37921 return data.node.ui.getDDRepairXY();
37924 onEndDrag : function(data, e){
37925 this.tree.fireEvent("enddrag", this.tree, data.node, e);
37930 onValidDrop : function(dd, e, id){
37931 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
37935 beforeInvalidDrop : function(e, id){
37936 // this scrolls the original position back into view
37937 var sm = this.tree.getSelectionModel();
37938 sm.clearSelections();
37939 sm.select(this.dragData.node);
37944 * Ext JS Library 1.1.1
37945 * Copyright(c) 2006-2007, Ext JS, LLC.
37947 * Originally Released Under LGPL - original licence link has changed is not relivant.
37950 * <script type="text/javascript">
37953 * @class Roo.tree.TreeEditor
37954 * @extends Roo.Editor
37955 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
37956 * as the editor field.
37958 * @param {Object} config (used to be the tree panel.)
37959 * @param {Object} oldconfig DEPRECIATED Either a prebuilt {@link Roo.form.Field} instance or a Field config object
37961 * @cfg {Roo.tree.TreePanel} tree The tree to bind to.
37962 * @cfg {Roo.form.TextField} field [required] The field configuration
37966 Roo.tree.TreeEditor = function(config, oldconfig) { // was -- (tree, config){
37969 if (oldconfig) { // old style..
37970 field = oldconfig.events ? oldconfig : new Roo.form.TextField(oldconfig);
37973 tree = config.tree;
37974 config.field = config.field || {};
37975 config.field.xtype = 'TextField';
37976 field = Roo.factory(config.field, Roo.form);
37978 config = config || {};
37983 * @event beforenodeedit
37984 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
37985 * false from the handler of this event.
37986 * @param {Editor} this
37987 * @param {Roo.tree.Node} node
37989 "beforenodeedit" : true
37993 Roo.tree.TreeEditor.superclass.constructor.call(this, field, config);
37997 tree.on('beforeclick', this.beforeNodeClick, this);
37998 tree.getTreeEl().on('mousedown', this.hide, this);
37999 this.on('complete', this.updateNode, this);
38000 this.on('beforestartedit', this.fitToTree, this);
38001 this.on('startedit', this.bindScroll, this, {delay:10});
38002 this.on('specialkey', this.onSpecialKey, this);
38005 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
38007 * @cfg {String} alignment
38008 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
38014 * @cfg {Boolean} hideEl
38015 * True to hide the bound element while the editor is displayed (defaults to false)
38019 * @cfg {String} cls
38020 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
38022 cls: "x-small-editor x-tree-editor",
38024 * @cfg {Boolean} shim
38025 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
38031 * @cfg {Number} maxWidth
38032 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
38033 * the containing tree element's size, it will be automatically limited for you to the container width, taking
38034 * scroll and client offsets into account prior to each edit.
38041 fitToTree : function(ed, el){
38042 var td = this.tree.getTreeEl().dom, nd = el.dom;
38043 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
38044 td.scrollLeft = nd.offsetLeft;
38048 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
38049 this.setSize(w, '');
38051 return this.fireEvent('beforenodeedit', this, this.editNode);
38056 triggerEdit : function(node){
38057 this.completeEdit();
38058 this.editNode = node;
38059 this.startEdit(node.ui.textNode, node.text);
38063 bindScroll : function(){
38064 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
38068 beforeNodeClick : function(node, e){
38069 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
38070 this.lastClick = new Date();
38071 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
38073 this.triggerEdit(node);
38080 updateNode : function(ed, value){
38081 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
38082 this.editNode.setText(value);
38086 onHide : function(){
38087 Roo.tree.TreeEditor.superclass.onHide.call(this);
38089 this.editNode.ui.focus();
38094 onSpecialKey : function(field, e){
38095 var k = e.getKey();
38099 }else if(k == e.ENTER && !e.hasModifier()){
38101 this.completeEdit();
38104 });//<Script type="text/javascript">
38107 * Ext JS Library 1.1.1
38108 * Copyright(c) 2006-2007, Ext JS, LLC.
38110 * Originally Released Under LGPL - original licence link has changed is not relivant.
38113 * <script type="text/javascript">
38117 * Not documented??? - probably should be...
38120 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
38121 //focus: Roo.emptyFn, // prevent odd scrolling behavior
38123 renderElements : function(n, a, targetNode, bulkRender){
38124 //consel.log("renderElements?");
38125 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
38127 var t = n.getOwnerTree();
38128 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
38130 var cols = t.columns;
38131 var bw = t.borderWidth;
38133 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
38134 var cb = typeof a.checked == "boolean";
38135 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
38136 var colcls = 'x-t-' + tid + '-c0';
38138 '<li class="x-tree-node">',
38141 '<div class="x-tree-node-el ', a.cls,'">',
38143 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
38146 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
38147 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
38148 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
38149 (a.icon ? ' x-tree-node-inline-icon' : ''),
38150 (a.iconCls ? ' '+a.iconCls : ''),
38151 '" unselectable="on" />',
38152 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
38153 (a.checked ? 'checked="checked" />' : ' />')) : ''),
38155 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
38156 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
38157 '<span unselectable="on" qtip="' + tx + '">',
38161 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
38162 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
38164 for(var i = 1, len = cols.length; i < len; i++){
38166 colcls = 'x-t-' + tid + '-c' +i;
38167 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
38168 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
38169 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
38175 '<div class="x-clear"></div></div>',
38176 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
38179 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
38180 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
38181 n.nextSibling.ui.getEl(), buf.join(""));
38183 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
38185 var el = this.wrap.firstChild;
38187 this.elNode = el.firstChild;
38188 this.ranchor = el.childNodes[1];
38189 this.ctNode = this.wrap.childNodes[1];
38190 var cs = el.firstChild.childNodes;
38191 this.indentNode = cs[0];
38192 this.ecNode = cs[1];
38193 this.iconNode = cs[2];
38196 this.checkbox = cs[3];
38199 this.anchor = cs[index];
38201 this.textNode = cs[index].firstChild;
38203 //el.on("click", this.onClick, this);
38204 //el.on("dblclick", this.onDblClick, this);
38207 // console.log(this);
38209 initEvents : function(){
38210 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
38213 var a = this.ranchor;
38215 var el = Roo.get(a);
38217 if(Roo.isOpera){ // opera render bug ignores the CSS
38218 el.setStyle("text-decoration", "none");
38221 el.on("click", this.onClick, this);
38222 el.on("dblclick", this.onDblClick, this);
38223 el.on("contextmenu", this.onContextMenu, this);
38227 /*onSelectedChange : function(state){
38230 this.addClass("x-tree-selected");
38233 this.removeClass("x-tree-selected");
38236 addClass : function(cls){
38238 Roo.fly(this.elRow).addClass(cls);
38244 removeClass : function(cls){
38246 Roo.fly(this.elRow).removeClass(cls);
38252 });//<Script type="text/javascript">
38256 * Ext JS Library 1.1.1
38257 * Copyright(c) 2006-2007, Ext JS, LLC.
38259 * Originally Released Under LGPL - original licence link has changed is not relivant.
38262 * <script type="text/javascript">
38267 * @class Roo.tree.ColumnTree
38268 * @extends Roo.tree.TreePanel
38269 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
38270 * @cfg {int} borderWidth compined right/left border allowance
38272 * @param {String/HTMLElement/Element} el The container element
38273 * @param {Object} config
38275 Roo.tree.ColumnTree = function(el, config)
38277 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
38281 * Fire this event on a container when it resizes
38282 * @param {int} w Width
38283 * @param {int} h Height
38287 this.on('resize', this.onResize, this);
38290 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
38294 borderWidth: Roo.isBorderBox ? 0 : 2,
38297 render : function(){
38298 // add the header.....
38300 Roo.tree.ColumnTree.superclass.render.apply(this);
38302 this.el.addClass('x-column-tree');
38304 this.headers = this.el.createChild(
38305 {cls:'x-tree-headers'},this.innerCt.dom);
38307 var cols = this.columns, c;
38308 var totalWidth = 0;
38310 var len = cols.length;
38311 for(var i = 0; i < len; i++){
38313 totalWidth += c.width;
38314 this.headEls.push(this.headers.createChild({
38315 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
38317 cls:'x-tree-hd-text',
38320 style:'width:'+(c.width-this.borderWidth)+'px;'
38323 this.headers.createChild({cls:'x-clear'});
38324 // prevent floats from wrapping when clipped
38325 this.headers.setWidth(totalWidth);
38326 //this.innerCt.setWidth(totalWidth);
38327 this.innerCt.setStyle({ overflow: 'auto' });
38328 this.onResize(this.width, this.height);
38332 onResize : function(w,h)
38337 this.innerCt.setWidth(this.width);
38338 this.innerCt.setHeight(this.height-20);
38341 var cols = this.columns, c;
38342 var totalWidth = 0;
38344 var len = cols.length;
38345 for(var i = 0; i < len; i++){
38347 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
38348 // it's the expander..
38349 expEl = this.headEls[i];
38352 totalWidth += c.width;
38356 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
38358 this.headers.setWidth(w-20);
38367 * Ext JS Library 1.1.1
38368 * Copyright(c) 2006-2007, Ext JS, LLC.
38370 * Originally Released Under LGPL - original licence link has changed is not relivant.
38373 * <script type="text/javascript">
38377 * @class Roo.menu.Menu
38378 * @extends Roo.util.Observable
38379 * @children Roo.menu.BaseItem
38380 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
38381 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
38383 * Creates a new Menu
38384 * @param {Object} config Configuration options
38386 Roo.menu.Menu = function(config){
38388 Roo.menu.Menu.superclass.constructor.call(this, config);
38390 this.id = this.id || Roo.id();
38393 * @event beforeshow
38394 * Fires before this menu is displayed
38395 * @param {Roo.menu.Menu} this
38399 * @event beforehide
38400 * Fires before this menu is hidden
38401 * @param {Roo.menu.Menu} this
38406 * Fires after this menu is displayed
38407 * @param {Roo.menu.Menu} this
38412 * Fires after this menu is hidden
38413 * @param {Roo.menu.Menu} this
38418 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
38419 * @param {Roo.menu.Menu} this
38420 * @param {Roo.menu.Item} menuItem The menu item that was clicked
38421 * @param {Roo.EventObject} e
38426 * Fires when the mouse is hovering over this menu
38427 * @param {Roo.menu.Menu} this
38428 * @param {Roo.EventObject} e
38429 * @param {Roo.menu.Item} menuItem The menu item that was clicked
38434 * Fires when the mouse exits this menu
38435 * @param {Roo.menu.Menu} this
38436 * @param {Roo.EventObject} e
38437 * @param {Roo.menu.Item} menuItem The menu item that was clicked
38442 * Fires when a menu item contained in this menu is clicked
38443 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
38444 * @param {Roo.EventObject} e
38448 if (this.registerMenu) {
38449 Roo.menu.MenuMgr.register(this);
38452 var mis = this.items;
38453 this.items = new Roo.util.MixedCollection();
38455 this.add.apply(this, mis);
38459 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
38461 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
38465 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
38466 * for bottom-right shadow (defaults to "sides")
38470 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
38471 * this menu (defaults to "tl-tr?")
38473 subMenuAlign : "tl-tr?",
38475 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
38476 * relative to its element of origin (defaults to "tl-bl?")
38478 defaultAlign : "tl-bl?",
38480 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
38482 allowOtherMenus : false,
38484 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
38486 registerMenu : true,
38491 render : function(){
38495 var el = this.el = new Roo.Layer({
38497 shadow:this.shadow,
38499 parentEl: this.parentEl || document.body,
38503 this.keyNav = new Roo.menu.MenuNav(this);
38506 el.addClass("x-menu-plain");
38509 el.addClass(this.cls);
38511 // generic focus element
38512 this.focusEl = el.createChild({
38513 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
38515 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
38516 //disabling touch- as it's causing issues ..
38517 //ul.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
38518 ul.on('click' , this.onClick, this);
38521 ul.on("mouseover", this.onMouseOver, this);
38522 ul.on("mouseout", this.onMouseOut, this);
38523 this.items.each(function(item){
38528 var li = document.createElement("li");
38529 li.className = "x-menu-list-item";
38530 ul.dom.appendChild(li);
38531 item.render(li, this);
38538 autoWidth : function(){
38539 var el = this.el, ul = this.ul;
38543 var w = this.width;
38546 }else if(Roo.isIE){
38547 el.setWidth(this.minWidth);
38548 var t = el.dom.offsetWidth; // force recalc
38549 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
38554 delayAutoWidth : function(){
38557 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
38559 this.awTask.delay(20);
38564 findTargetItem : function(e){
38565 var t = e.getTarget(".x-menu-list-item", this.ul, true);
38566 if(t && t.menuItemId){
38567 return this.items.get(t.menuItemId);
38572 onClick : function(e){
38573 Roo.log("menu.onClick");
38574 var t = this.findTargetItem(e);
38579 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
38580 if(t == this.activeItem && t.shouldDeactivate(e)){
38581 this.activeItem.deactivate();
38582 delete this.activeItem;
38586 this.setActiveItem(t, true);
38594 this.fireEvent("click", this, t, e);
38598 setActiveItem : function(item, autoExpand){
38599 if(item != this.activeItem){
38600 if(this.activeItem){
38601 this.activeItem.deactivate();
38603 this.activeItem = item;
38604 item.activate(autoExpand);
38605 }else if(autoExpand){
38611 tryActivate : function(start, step){
38612 var items = this.items;
38613 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
38614 var item = items.get(i);
38615 if(!item.disabled && item.canActivate){
38616 this.setActiveItem(item, false);
38624 onMouseOver : function(e){
38626 if(t = this.findTargetItem(e)){
38627 if(t.canActivate && !t.disabled){
38628 this.setActiveItem(t, true);
38631 this.fireEvent("mouseover", this, e, t);
38635 onMouseOut : function(e){
38637 if(t = this.findTargetItem(e)){
38638 if(t == this.activeItem && t.shouldDeactivate(e)){
38639 this.activeItem.deactivate();
38640 delete this.activeItem;
38643 this.fireEvent("mouseout", this, e, t);
38647 * Read-only. Returns true if the menu is currently displayed, else false.
38650 isVisible : function(){
38651 return this.el && !this.hidden;
38655 * Displays this menu relative to another element
38656 * @param {String/HTMLElement/Roo.Element} element The element to align to
38657 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
38658 * the element (defaults to this.defaultAlign)
38659 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
38661 show : function(el, pos, parentMenu){
38662 this.parentMenu = parentMenu;
38666 this.fireEvent("beforeshow", this);
38667 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
38671 * Displays this menu at a specific xy position
38672 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
38673 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
38675 showAt : function(xy, parentMenu, /* private: */_e){
38676 this.parentMenu = parentMenu;
38681 this.fireEvent("beforeshow", this);
38682 xy = this.el.adjustForConstraints(xy);
38686 this.hidden = false;
38688 this.fireEvent("show", this);
38691 focus : function(){
38693 this.doFocus.defer(50, this);
38697 doFocus : function(){
38699 this.focusEl.focus();
38704 * Hides this menu and optionally all parent menus
38705 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
38707 hide : function(deep){
38708 if(this.el && this.isVisible()){
38709 this.fireEvent("beforehide", this);
38710 if(this.activeItem){
38711 this.activeItem.deactivate();
38712 this.activeItem = null;
38715 this.hidden = true;
38716 this.fireEvent("hide", this);
38718 if(deep === true && this.parentMenu){
38719 this.parentMenu.hide(true);
38724 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
38725 * Any of the following are valid:
38727 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
38728 * <li>An HTMLElement object which will be converted to a menu item</li>
38729 * <li>A menu item config object that will be created as a new menu item</li>
38730 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
38731 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
38736 var menu = new Roo.menu.Menu();
38738 // Create a menu item to add by reference
38739 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
38741 // Add a bunch of items at once using different methods.
38742 // Only the last item added will be returned.
38743 var item = menu.add(
38744 menuItem, // add existing item by ref
38745 'Dynamic Item', // new TextItem
38746 '-', // new separator
38747 { text: 'Config Item' } // new item by config
38750 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
38751 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
38754 var a = arguments, l = a.length, item;
38755 for(var i = 0; i < l; i++){
38757 if ((typeof(el) == "object") && el.xtype && el.xns) {
38758 el = Roo.factory(el, Roo.menu);
38761 if(el.render){ // some kind of Item
38762 item = this.addItem(el);
38763 }else if(typeof el == "string"){ // string
38764 if(el == "separator" || el == "-"){
38765 item = this.addSeparator();
38767 item = this.addText(el);
38769 }else if(el.tagName || el.el){ // element
38770 item = this.addElement(el);
38771 }else if(typeof el == "object"){ // must be menu item config?
38772 item = this.addMenuItem(el);
38779 * Returns this menu's underlying {@link Roo.Element} object
38780 * @return {Roo.Element} The element
38782 getEl : function(){
38790 * Adds a separator bar to the menu
38791 * @return {Roo.menu.Item} The menu item that was added
38793 addSeparator : function(){
38794 return this.addItem(new Roo.menu.Separator());
38798 * Adds an {@link Roo.Element} object to the menu
38799 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
38800 * @return {Roo.menu.Item} The menu item that was added
38802 addElement : function(el){
38803 return this.addItem(new Roo.menu.BaseItem(el));
38807 * Adds an existing object based on {@link Roo.menu.Item} to the menu
38808 * @param {Roo.menu.Item} item The menu item to add
38809 * @return {Roo.menu.Item} The menu item that was added
38811 addItem : function(item){
38812 this.items.add(item);
38814 var li = document.createElement("li");
38815 li.className = "x-menu-list-item";
38816 this.ul.dom.appendChild(li);
38817 item.render(li, this);
38818 this.delayAutoWidth();
38824 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
38825 * @param {Object} config A MenuItem config object
38826 * @return {Roo.menu.Item} The menu item that was added
38828 addMenuItem : function(config){
38829 if(!(config instanceof Roo.menu.Item)){
38830 if(typeof config.checked == "boolean"){ // must be check menu item config?
38831 config = new Roo.menu.CheckItem(config);
38833 config = new Roo.menu.Item(config);
38836 return this.addItem(config);
38840 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
38841 * @param {String} text The text to display in the menu item
38842 * @return {Roo.menu.Item} The menu item that was added
38844 addText : function(text){
38845 return this.addItem(new Roo.menu.TextItem({ text : text }));
38849 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
38850 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
38851 * @param {Roo.menu.Item} item The menu item to add
38852 * @return {Roo.menu.Item} The menu item that was added
38854 insert : function(index, item){
38855 this.items.insert(index, item);
38857 var li = document.createElement("li");
38858 li.className = "x-menu-list-item";
38859 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
38860 item.render(li, this);
38861 this.delayAutoWidth();
38867 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
38868 * @param {Roo.menu.Item} item The menu item to remove
38870 remove : function(item){
38871 this.items.removeKey(item.id);
38876 * Removes and destroys all items in the menu
38878 removeAll : function(){
38880 while(f = this.items.first()){
38886 // MenuNav is a private utility class used internally by the Menu
38887 Roo.menu.MenuNav = function(menu){
38888 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
38889 this.scope = this.menu = menu;
38892 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
38893 doRelay : function(e, h){
38894 var k = e.getKey();
38895 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
38896 this.menu.tryActivate(0, 1);
38899 return h.call(this.scope || this, e, this.menu);
38902 up : function(e, m){
38903 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
38904 m.tryActivate(m.items.length-1, -1);
38908 down : function(e, m){
38909 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
38910 m.tryActivate(0, 1);
38914 right : function(e, m){
38916 m.activeItem.expandMenu(true);
38920 left : function(e, m){
38922 if(m.parentMenu && m.parentMenu.activeItem){
38923 m.parentMenu.activeItem.activate();
38927 enter : function(e, m){
38929 e.stopPropagation();
38930 m.activeItem.onClick(e);
38931 m.fireEvent("click", this, m.activeItem);
38937 * Ext JS Library 1.1.1
38938 * Copyright(c) 2006-2007, Ext JS, LLC.
38940 * Originally Released Under LGPL - original licence link has changed is not relivant.
38943 * <script type="text/javascript">
38947 * @class Roo.menu.MenuMgr
38948 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
38951 Roo.menu.MenuMgr = function(){
38952 var menus, active, groups = {}, attached = false, lastShow = new Date();
38954 // private - called when first menu is created
38957 active = new Roo.util.MixedCollection();
38958 Roo.get(document).addKeyListener(27, function(){
38959 if(active.length > 0){
38966 function hideAll(){
38967 if(active && active.length > 0){
38968 var c = active.clone();
38969 c.each(function(m){
38976 function onHide(m){
38978 if(active.length < 1){
38979 Roo.get(document).un("mousedown", onMouseDown);
38985 function onShow(m){
38986 var last = active.last();
38987 lastShow = new Date();
38990 Roo.get(document).on("mousedown", onMouseDown);
38994 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
38995 m.parentMenu.activeChild = m;
38996 }else if(last && last.isVisible()){
38997 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
39002 function onBeforeHide(m){
39004 m.activeChild.hide();
39006 if(m.autoHideTimer){
39007 clearTimeout(m.autoHideTimer);
39008 delete m.autoHideTimer;
39013 function onBeforeShow(m){
39014 var pm = m.parentMenu;
39015 if(!pm && !m.allowOtherMenus){
39017 }else if(pm && pm.activeChild && active != m){
39018 pm.activeChild.hide();
39023 function onMouseDown(e){
39024 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
39030 function onBeforeCheck(mi, state){
39032 var g = groups[mi.group];
39033 for(var i = 0, l = g.length; i < l; i++){
39035 g[i].setChecked(false);
39044 * Hides all menus that are currently visible
39046 hideAll : function(){
39051 register : function(menu){
39055 menus[menu.id] = menu;
39056 menu.on("beforehide", onBeforeHide);
39057 menu.on("hide", onHide);
39058 menu.on("beforeshow", onBeforeShow);
39059 menu.on("show", onShow);
39060 var g = menu.group;
39061 if(g && menu.events["checkchange"]){
39065 groups[g].push(menu);
39066 menu.on("checkchange", onCheck);
39071 * Returns a {@link Roo.menu.Menu} object
39072 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
39073 * be used to generate and return a new Menu instance.
39075 get : function(menu){
39076 if(typeof menu == "string"){ // menu id
39077 return menus[menu];
39078 }else if(menu.events){ // menu instance
39080 }else if(typeof menu.length == 'number'){ // array of menu items?
39081 return new Roo.menu.Menu({items:menu});
39082 }else{ // otherwise, must be a config
39083 return new Roo.menu.Menu(menu);
39088 unregister : function(menu){
39089 delete menus[menu.id];
39090 menu.un("beforehide", onBeforeHide);
39091 menu.un("hide", onHide);
39092 menu.un("beforeshow", onBeforeShow);
39093 menu.un("show", onShow);
39094 var g = menu.group;
39095 if(g && menu.events["checkchange"]){
39096 groups[g].remove(menu);
39097 menu.un("checkchange", onCheck);
39102 registerCheckable : function(menuItem){
39103 var g = menuItem.group;
39108 groups[g].push(menuItem);
39109 menuItem.on("beforecheckchange", onBeforeCheck);
39114 unregisterCheckable : function(menuItem){
39115 var g = menuItem.group;
39117 groups[g].remove(menuItem);
39118 menuItem.un("beforecheckchange", onBeforeCheck);
39124 * Ext JS Library 1.1.1
39125 * Copyright(c) 2006-2007, Ext JS, LLC.
39127 * Originally Released Under LGPL - original licence link has changed is not relivant.
39130 * <script type="text/javascript">
39135 * @class Roo.menu.BaseItem
39136 * @extends Roo.Component
39138 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
39139 * management and base configuration options shared by all menu components.
39141 * Creates a new BaseItem
39142 * @param {Object} config Configuration options
39144 Roo.menu.BaseItem = function(config){
39145 Roo.menu.BaseItem.superclass.constructor.call(this, config);
39150 * Fires when this item is clicked
39151 * @param {Roo.menu.BaseItem} this
39152 * @param {Roo.EventObject} e
39157 * Fires when this item is activated
39158 * @param {Roo.menu.BaseItem} this
39162 * @event deactivate
39163 * Fires when this item is deactivated
39164 * @param {Roo.menu.BaseItem} this
39170 this.on("click", this.handler, this.scope, true);
39174 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
39176 * @cfg {Function} handler
39177 * A function that will handle the click event of this menu item (defaults to undefined)
39180 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
39182 canActivate : false,
39185 * @cfg {Boolean} hidden True to prevent creation of this menu item (defaults to false)
39190 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
39192 activeClass : "x-menu-item-active",
39194 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
39196 hideOnClick : true,
39198 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
39203 ctype: "Roo.menu.BaseItem",
39206 actionMode : "container",
39209 render : function(container, parentMenu){
39210 this.parentMenu = parentMenu;
39211 Roo.menu.BaseItem.superclass.render.call(this, container);
39212 this.container.menuItemId = this.id;
39216 onRender : function(container, position){
39217 this.el = Roo.get(this.el);
39218 container.dom.appendChild(this.el.dom);
39222 onClick : function(e){
39223 if(!this.disabled && this.fireEvent("click", this, e) !== false
39224 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
39225 this.handleClick(e);
39232 activate : function(){
39236 var li = this.container;
39237 li.addClass(this.activeClass);
39238 this.region = li.getRegion().adjust(2, 2, -2, -2);
39239 this.fireEvent("activate", this);
39244 deactivate : function(){
39245 this.container.removeClass(this.activeClass);
39246 this.fireEvent("deactivate", this);
39250 shouldDeactivate : function(e){
39251 return !this.region || !this.region.contains(e.getPoint());
39255 handleClick : function(e){
39256 if(this.hideOnClick){
39257 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
39262 expandMenu : function(autoActivate){
39267 hideMenu : function(){
39272 * Ext JS Library 1.1.1
39273 * Copyright(c) 2006-2007, Ext JS, LLC.
39275 * Originally Released Under LGPL - original licence link has changed is not relivant.
39278 * <script type="text/javascript">
39282 * @class Roo.menu.Adapter
39283 * @extends Roo.menu.BaseItem
39285 * 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.
39286 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
39288 * Creates a new Adapter
39289 * @param {Object} config Configuration options
39291 Roo.menu.Adapter = function(component, config){
39292 Roo.menu.Adapter.superclass.constructor.call(this, config);
39293 this.component = component;
39295 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
39297 canActivate : true,
39300 onRender : function(container, position){
39301 this.component.render(container);
39302 this.el = this.component.getEl();
39306 activate : function(){
39310 this.component.focus();
39311 this.fireEvent("activate", this);
39316 deactivate : function(){
39317 this.fireEvent("deactivate", this);
39321 disable : function(){
39322 this.component.disable();
39323 Roo.menu.Adapter.superclass.disable.call(this);
39327 enable : function(){
39328 this.component.enable();
39329 Roo.menu.Adapter.superclass.enable.call(this);
39333 * Ext JS Library 1.1.1
39334 * Copyright(c) 2006-2007, Ext JS, LLC.
39336 * Originally Released Under LGPL - original licence link has changed is not relivant.
39339 * <script type="text/javascript">
39343 * @class Roo.menu.TextItem
39344 * @extends Roo.menu.BaseItem
39345 * Adds a static text string to a menu, usually used as either a heading or group separator.
39346 * Note: old style constructor with text is still supported.
39349 * Creates a new TextItem
39350 * @param {Object} cfg Configuration
39352 Roo.menu.TextItem = function(cfg){
39353 if (typeof(cfg) == 'string') {
39356 Roo.apply(this,cfg);
39359 Roo.menu.TextItem.superclass.constructor.call(this);
39362 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
39364 * @cfg {String} text Text to show on item.
39369 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
39371 hideOnClick : false,
39373 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
39375 itemCls : "x-menu-text",
39378 onRender : function(){
39379 var s = document.createElement("span");
39380 s.className = this.itemCls;
39381 s.innerHTML = this.text;
39383 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
39387 * Ext JS Library 1.1.1
39388 * Copyright(c) 2006-2007, Ext JS, LLC.
39390 * Originally Released Under LGPL - original licence link has changed is not relivant.
39393 * <script type="text/javascript">
39397 * @class Roo.menu.Separator
39398 * @extends Roo.menu.BaseItem
39399 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
39400 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
39402 * @param {Object} config Configuration options
39404 Roo.menu.Separator = function(config){
39405 Roo.menu.Separator.superclass.constructor.call(this, config);
39408 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
39410 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
39412 itemCls : "x-menu-sep",
39414 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
39416 hideOnClick : false,
39419 onRender : function(li){
39420 var s = document.createElement("span");
39421 s.className = this.itemCls;
39422 s.innerHTML = " ";
39424 li.addClass("x-menu-sep-li");
39425 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
39429 * Ext JS Library 1.1.1
39430 * Copyright(c) 2006-2007, Ext JS, LLC.
39432 * Originally Released Under LGPL - original licence link has changed is not relivant.
39435 * <script type="text/javascript">
39438 * @class Roo.menu.Item
39439 * @extends Roo.menu.BaseItem
39440 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
39441 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
39442 * activation and click handling.
39444 * Creates a new Item
39445 * @param {Object} config Configuration options
39447 Roo.menu.Item = function(config){
39448 Roo.menu.Item.superclass.constructor.call(this, config);
39450 this.menu = Roo.menu.MenuMgr.get(this.menu);
39453 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
39455 * @cfg {Roo.menu.Menu} menu
39459 * @cfg {String} text
39460 * The text to show on the menu item.
39464 * @cfg {String} HTML to render in menu
39465 * The text to show on the menu item (HTML version).
39469 * @cfg {String} icon
39470 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
39474 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
39476 itemCls : "x-menu-item",
39478 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
39480 canActivate : true,
39482 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
39485 // doc'd in BaseItem
39489 ctype: "Roo.menu.Item",
39492 onRender : function(container, position){
39493 var el = document.createElement("a");
39494 el.hideFocus = true;
39495 el.unselectable = "on";
39496 el.href = this.href || "#";
39497 if(this.hrefTarget){
39498 el.target = this.hrefTarget;
39500 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
39502 var html = this.html.length ? this.html : String.format('{0}',this.text);
39504 el.innerHTML = String.format(
39505 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
39506 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
39508 Roo.menu.Item.superclass.onRender.call(this, container, position);
39512 * Sets the text to display in this menu item
39513 * @param {String} text The text to display
39514 * @param {Boolean} isHTML true to indicate text is pure html.
39516 setText : function(text, isHTML){
39524 var html = this.html.length ? this.html : String.format('{0}',this.text);
39526 this.el.update(String.format(
39527 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
39528 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
39529 this.parentMenu.autoWidth();
39534 handleClick : function(e){
39535 if(!this.href){ // if no link defined, stop the event automatically
39538 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
39542 activate : function(autoExpand){
39543 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
39553 shouldDeactivate : function(e){
39554 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
39555 if(this.menu && this.menu.isVisible()){
39556 return !this.menu.getEl().getRegion().contains(e.getPoint());
39564 deactivate : function(){
39565 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
39570 expandMenu : function(autoActivate){
39571 if(!this.disabled && this.menu){
39572 clearTimeout(this.hideTimer);
39573 delete this.hideTimer;
39574 if(!this.menu.isVisible() && !this.showTimer){
39575 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
39576 }else if (this.menu.isVisible() && autoActivate){
39577 this.menu.tryActivate(0, 1);
39583 deferExpand : function(autoActivate){
39584 delete this.showTimer;
39585 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
39587 this.menu.tryActivate(0, 1);
39592 hideMenu : function(){
39593 clearTimeout(this.showTimer);
39594 delete this.showTimer;
39595 if(!this.hideTimer && this.menu && this.menu.isVisible()){
39596 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
39601 deferHide : function(){
39602 delete this.hideTimer;
39607 * Ext JS Library 1.1.1
39608 * Copyright(c) 2006-2007, Ext JS, LLC.
39610 * Originally Released Under LGPL - original licence link has changed is not relivant.
39613 * <script type="text/javascript">
39617 * @class Roo.menu.CheckItem
39618 * @extends Roo.menu.Item
39619 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
39621 * Creates a new CheckItem
39622 * @param {Object} config Configuration options
39624 Roo.menu.CheckItem = function(config){
39625 Roo.menu.CheckItem.superclass.constructor.call(this, config);
39628 * @event beforecheckchange
39629 * Fires before the checked value is set, providing an opportunity to cancel if needed
39630 * @param {Roo.menu.CheckItem} this
39631 * @param {Boolean} checked The new checked value that will be set
39633 "beforecheckchange" : true,
39635 * @event checkchange
39636 * Fires after the checked value has been set
39637 * @param {Roo.menu.CheckItem} this
39638 * @param {Boolean} checked The checked value that was set
39640 "checkchange" : true
39642 if(this.checkHandler){
39643 this.on('checkchange', this.checkHandler, this.scope);
39646 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
39648 * @cfg {String} group
39649 * All check items with the same group name will automatically be grouped into a single-select
39650 * radio button group (defaults to '')
39653 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
39655 itemCls : "x-menu-item x-menu-check-item",
39657 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
39659 groupClass : "x-menu-group-item",
39662 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
39663 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
39664 * initialized with checked = true will be rendered as checked.
39669 ctype: "Roo.menu.CheckItem",
39672 onRender : function(c){
39673 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
39675 this.el.addClass(this.groupClass);
39677 Roo.menu.MenuMgr.registerCheckable(this);
39679 this.checked = false;
39680 this.setChecked(true, true);
39685 destroy : function(){
39687 Roo.menu.MenuMgr.unregisterCheckable(this);
39689 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
39693 * Set the checked state of this item
39694 * @param {Boolean} checked The new checked value
39695 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
39697 setChecked : function(state, suppressEvent){
39698 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
39699 if(this.container){
39700 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
39702 this.checked = state;
39703 if(suppressEvent !== true){
39704 this.fireEvent("checkchange", this, state);
39710 handleClick : function(e){
39711 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
39712 this.setChecked(!this.checked);
39714 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
39718 * Ext JS Library 1.1.1
39719 * Copyright(c) 2006-2007, Ext JS, LLC.
39721 * Originally Released Under LGPL - original licence link has changed is not relivant.
39724 * <script type="text/javascript">
39728 * @class Roo.menu.DateItem
39729 * @extends Roo.menu.Adapter
39730 * A menu item that wraps the {@link Roo.DatPicker} component.
39732 * Creates a new DateItem
39733 * @param {Object} config Configuration options
39735 Roo.menu.DateItem = function(config){
39736 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
39737 /** The Roo.DatePicker object @type Roo.DatePicker */
39738 this.picker = this.component;
39739 this.addEvents({select: true});
39741 this.picker.on("render", function(picker){
39742 picker.getEl().swallowEvent("click");
39743 picker.container.addClass("x-menu-date-item");
39746 this.picker.on("select", this.onSelect, this);
39749 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
39751 onSelect : function(picker, date){
39752 this.fireEvent("select", this, date, picker);
39753 Roo.menu.DateItem.superclass.handleClick.call(this);
39757 * Ext JS Library 1.1.1
39758 * Copyright(c) 2006-2007, Ext JS, LLC.
39760 * Originally Released Under LGPL - original licence link has changed is not relivant.
39763 * <script type="text/javascript">
39767 * @class Roo.menu.ColorItem
39768 * @extends Roo.menu.Adapter
39769 * A menu item that wraps the {@link Roo.ColorPalette} component.
39771 * Creates a new ColorItem
39772 * @param {Object} config Configuration options
39774 Roo.menu.ColorItem = function(config){
39775 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
39776 /** The Roo.ColorPalette object @type Roo.ColorPalette */
39777 this.palette = this.component;
39778 this.relayEvents(this.palette, ["select"]);
39779 if(this.selectHandler){
39780 this.on('select', this.selectHandler, this.scope);
39783 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
39785 * Ext JS Library 1.1.1
39786 * Copyright(c) 2006-2007, Ext JS, LLC.
39788 * Originally Released Under LGPL - original licence link has changed is not relivant.
39791 * <script type="text/javascript">
39796 * @class Roo.menu.DateMenu
39797 * @extends Roo.menu.Menu
39798 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
39800 * Creates a new DateMenu
39801 * @param {Object} config Configuration options
39803 Roo.menu.DateMenu = function(config){
39804 Roo.menu.DateMenu.superclass.constructor.call(this, config);
39806 var di = new Roo.menu.DateItem(config);
39809 * The {@link Roo.DatePicker} instance for this DateMenu
39812 this.picker = di.picker;
39815 * @param {DatePicker} picker
39816 * @param {Date} date
39818 this.relayEvents(di, ["select"]);
39819 this.on('beforeshow', function(){
39821 this.picker.hideMonthPicker(false);
39825 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
39829 * Ext JS Library 1.1.1
39830 * Copyright(c) 2006-2007, Ext JS, LLC.
39832 * Originally Released Under LGPL - original licence link has changed is not relivant.
39835 * <script type="text/javascript">
39840 * @class Roo.menu.ColorMenu
39841 * @extends Roo.menu.Menu
39842 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
39844 * Creates a new ColorMenu
39845 * @param {Object} config Configuration options
39847 Roo.menu.ColorMenu = function(config){
39848 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
39850 var ci = new Roo.menu.ColorItem(config);
39853 * The {@link Roo.ColorPalette} instance for this ColorMenu
39854 * @type ColorPalette
39856 this.palette = ci.palette;
39859 * @param {ColorPalette} palette
39860 * @param {String} color
39862 this.relayEvents(ci, ["select"]);
39864 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
39866 * Ext JS Library 1.1.1
39867 * Copyright(c) 2006-2007, Ext JS, LLC.
39869 * Originally Released Under LGPL - original licence link has changed is not relivant.
39872 * <script type="text/javascript">
39876 * @class Roo.form.TextItem
39877 * @extends Roo.BoxComponent
39878 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
39880 * Creates a new TextItem
39881 * @param {Object} config Configuration options
39883 Roo.form.TextItem = function(config){
39884 Roo.form.TextItem.superclass.constructor.call(this, config);
39887 Roo.extend(Roo.form.TextItem, Roo.BoxComponent, {
39890 * @cfg {String} tag the tag for this item (default div)
39894 * @cfg {String} html the content for this item
39898 getAutoCreate : function()
39911 onRender : function(ct, position)
39913 Roo.form.TextItem.superclass.onRender.call(this, ct, position);
39916 var cfg = this.getAutoCreate();
39918 cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
39920 if (!cfg.name.length) {
39923 this.el = ct.createChild(cfg, position);
39928 * @param {String} html update the Contents of the element.
39930 setHTML : function(html)
39932 this.fieldEl.dom.innerHTML = html;
39937 * Ext JS Library 1.1.1
39938 * Copyright(c) 2006-2007, Ext JS, LLC.
39940 * Originally Released Under LGPL - original licence link has changed is not relivant.
39943 * <script type="text/javascript">
39947 * @class Roo.form.Field
39948 * @extends Roo.BoxComponent
39949 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
39951 * Creates a new Field
39952 * @param {Object} config Configuration options
39954 Roo.form.Field = function(config){
39955 Roo.form.Field.superclass.constructor.call(this, config);
39958 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
39960 * @cfg {String} fieldLabel Label to use when rendering a form.
39963 * @cfg {String} qtip Mouse over tip
39967 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
39969 invalidClass : "x-form-invalid",
39971 * @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")
39973 invalidText : "The value in this field is invalid",
39975 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
39977 focusClass : "x-form-focus",
39979 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
39980 automatic validation (defaults to "keyup").
39982 validationEvent : "keyup",
39984 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
39986 validateOnBlur : true,
39988 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
39990 validationDelay : 250,
39992 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
39993 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
39995 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "new-password"},
39997 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
39999 fieldClass : "x-form-field",
40001 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
40004 ----------- ----------------------------------------------------------------------
40005 qtip Display a quick tip when the user hovers over the field
40006 title Display a default browser title attribute popup
40007 under Add a block div beneath the field containing the error text
40008 side Add an error icon to the right of the field with a popup on hover
40009 [element id] Add the error text directly to the innerHTML of the specified element
40012 msgTarget : 'qtip',
40014 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
40019 * @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.
40024 * @cfg {Boolean} disabled True to disable the field (defaults to false).
40029 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
40031 inputType : undefined,
40034 * @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).
40036 tabIndex : undefined,
40039 isFormField : true,
40044 * @property {Roo.Element} fieldEl
40045 * Element Containing the rendered Field (with label etc.)
40048 * @cfg {Mixed} value A value to initialize this field with.
40053 * @cfg {String} name The field's HTML name attribute.
40056 * @cfg {String} cls A CSS class to apply to the field's underlying element.
40059 loadedValue : false,
40063 initComponent : function(){
40064 Roo.form.Field.superclass.initComponent.call(this);
40068 * Fires when this field receives input focus.
40069 * @param {Roo.form.Field} this
40074 * Fires when this field loses input focus.
40075 * @param {Roo.form.Field} this
40079 * @event specialkey
40080 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
40081 * {@link Roo.EventObject#getKey} to determine which key was pressed.
40082 * @param {Roo.form.Field} this
40083 * @param {Roo.EventObject} e The event object
40088 * Fires just before the field blurs if the field value has changed.
40089 * @param {Roo.form.Field} this
40090 * @param {Mixed} newValue The new value
40091 * @param {Mixed} oldValue The original value
40096 * Fires after the field has been marked as invalid.
40097 * @param {Roo.form.Field} this
40098 * @param {String} msg The validation message
40103 * Fires after the field has been validated with no errors.
40104 * @param {Roo.form.Field} this
40109 * Fires after the key up
40110 * @param {Roo.form.Field} this
40111 * @param {Roo.EventObject} e The event Object
40118 * Returns the name attribute of the field if available
40119 * @return {String} name The field name
40121 getName: function(){
40122 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
40126 onRender : function(ct, position){
40127 Roo.form.Field.superclass.onRender.call(this, ct, position);
40129 var cfg = this.getAutoCreate();
40131 cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
40133 if (!cfg.name.length) {
40136 if(this.inputType){
40137 cfg.type = this.inputType;
40139 this.el = ct.createChild(cfg, position);
40141 var type = this.el.dom.type;
40143 if(type == 'password'){
40146 this.el.addClass('x-form-'+type);
40149 this.el.dom.readOnly = true;
40151 if(this.tabIndex !== undefined){
40152 this.el.dom.setAttribute('tabIndex', this.tabIndex);
40155 this.el.addClass([this.fieldClass, this.cls]);
40160 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
40161 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
40162 * @return {Roo.form.Field} this
40164 applyTo : function(target){
40165 this.allowDomMove = false;
40166 this.el = Roo.get(target);
40167 this.render(this.el.dom.parentNode);
40172 initValue : function(){
40173 if(this.value !== undefined){
40174 this.setValue(this.value);
40175 }else if(this.el.dom.value.length > 0){
40176 this.setValue(this.el.dom.value);
40181 * Returns true if this field has been changed since it was originally loaded and is not disabled.
40182 * DEPRICATED - it never worked well - use hasChanged/resetHasChanged.
40184 isDirty : function() {
40185 if(this.disabled) {
40188 return String(this.getValue()) !== String(this.originalValue);
40192 * stores the current value in loadedValue
40194 resetHasChanged : function()
40196 this.loadedValue = String(this.getValue());
40199 * checks the current value against the 'loaded' value.
40200 * Note - will return false if 'resetHasChanged' has not been called first.
40202 hasChanged : function()
40204 if(this.disabled || this.readOnly) {
40207 return this.loadedValue !== false && String(this.getValue()) !== this.loadedValue;
40213 afterRender : function(){
40214 Roo.form.Field.superclass.afterRender.call(this);
40219 fireKey : function(e){
40220 //Roo.log('field ' + e.getKey());
40221 if(e.isNavKeyPress()){
40222 this.fireEvent("specialkey", this, e);
40227 * Resets the current field value to the originally loaded value and clears any validation messages
40229 reset : function(){
40230 this.setValue(this.resetValue);
40231 this.originalValue = this.getValue();
40232 this.clearInvalid();
40236 initEvents : function(){
40237 // safari killled keypress - so keydown is now used..
40238 this.el.on("keydown" , this.fireKey, this);
40239 this.el.on("focus", this.onFocus, this);
40240 this.el.on("blur", this.onBlur, this);
40241 this.el.relayEvent('keyup', this);
40243 // reference to original value for reset
40244 this.originalValue = this.getValue();
40245 this.resetValue = this.getValue();
40249 onFocus : function(){
40250 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
40251 this.el.addClass(this.focusClass);
40253 if(!this.hasFocus){
40254 this.hasFocus = true;
40255 this.startValue = this.getValue();
40256 this.fireEvent("focus", this);
40260 beforeBlur : Roo.emptyFn,
40263 onBlur : function(){
40265 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
40266 this.el.removeClass(this.focusClass);
40268 this.hasFocus = false;
40269 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
40272 var v = this.getValue();
40273 if(String(v) !== String(this.startValue)){
40274 this.fireEvent('change', this, v, this.startValue);
40276 this.fireEvent("blur", this);
40280 * Returns whether or not the field value is currently valid
40281 * @param {Boolean} preventMark True to disable marking the field invalid
40282 * @return {Boolean} True if the value is valid, else false
40284 isValid : function(preventMark){
40288 var restore = this.preventMark;
40289 this.preventMark = preventMark === true;
40290 var v = this.validateValue(this.processValue(this.getRawValue()));
40291 this.preventMark = restore;
40296 * Validates the field value
40297 * @return {Boolean} True if the value is valid, else false
40299 validate : function(){
40300 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
40301 this.clearInvalid();
40307 processValue : function(value){
40312 // Subclasses should provide the validation implementation by overriding this
40313 validateValue : function(value){
40318 * Mark this field as invalid
40319 * @param {String} msg The validation message
40321 markInvalid : function(msg){
40322 if(!this.rendered || this.preventMark){ // not rendered
40326 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
40328 obj.el.addClass(this.invalidClass);
40329 msg = msg || this.invalidText;
40330 switch(this.msgTarget){
40332 obj.el.dom.qtip = msg;
40333 obj.el.dom.qclass = 'x-form-invalid-tip';
40334 if(Roo.QuickTips){ // fix for floating editors interacting with DND
40335 Roo.QuickTips.enable();
40339 this.el.dom.title = msg;
40343 var elp = this.el.findParent('.x-form-element', 5, true);
40344 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
40345 this.errorEl.setWidth(elp.getWidth(true)-20);
40347 this.errorEl.update(msg);
40348 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
40351 if(!this.errorIcon){
40352 var elp = this.el.findParent('.x-form-element', 5, true);
40353 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
40355 this.alignErrorIcon();
40356 this.errorIcon.dom.qtip = msg;
40357 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
40358 this.errorIcon.show();
40359 this.on('resize', this.alignErrorIcon, this);
40362 var t = Roo.getDom(this.msgTarget);
40364 t.style.display = this.msgDisplay;
40367 this.fireEvent('invalid', this, msg);
40371 alignErrorIcon : function(){
40372 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
40376 * Clear any invalid styles/messages for this field
40378 clearInvalid : function(){
40379 if(!this.rendered || this.preventMark){ // not rendered
40382 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
40384 obj.el.removeClass(this.invalidClass);
40385 switch(this.msgTarget){
40387 obj.el.dom.qtip = '';
40390 this.el.dom.title = '';
40394 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
40398 if(this.errorIcon){
40399 this.errorIcon.dom.qtip = '';
40400 this.errorIcon.hide();
40401 this.un('resize', this.alignErrorIcon, this);
40405 var t = Roo.getDom(this.msgTarget);
40407 t.style.display = 'none';
40410 this.fireEvent('valid', this);
40414 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
40415 * @return {Mixed} value The field value
40417 getRawValue : function(){
40418 var v = this.el.getValue();
40424 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
40425 * @return {Mixed} value The field value
40427 getValue : function(){
40428 var v = this.el.getValue();
40434 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
40435 * @param {Mixed} value The value to set
40437 setRawValue : function(v){
40438 return this.el.dom.value = (v === null || v === undefined ? '' : v);
40442 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
40443 * @param {Mixed} value The value to set
40445 setValue : function(v){
40448 this.el.dom.value = (v === null || v === undefined ? '' : v);
40453 adjustSize : function(w, h){
40454 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
40455 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
40459 adjustWidth : function(tag, w){
40460 tag = tag.toLowerCase();
40461 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
40462 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
40463 if(tag == 'input'){
40466 if(tag == 'textarea'){
40469 }else if(Roo.isOpera){
40470 if(tag == 'input'){
40473 if(tag == 'textarea'){
40483 // anything other than normal should be considered experimental
40484 Roo.form.Field.msgFx = {
40486 show: function(msgEl, f){
40487 msgEl.setDisplayed('block');
40490 hide : function(msgEl, f){
40491 msgEl.setDisplayed(false).update('');
40496 show: function(msgEl, f){
40497 msgEl.slideIn('t', {stopFx:true});
40500 hide : function(msgEl, f){
40501 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
40506 show: function(msgEl, f){
40507 msgEl.fixDisplay();
40508 msgEl.alignTo(f.el, 'tl-tr');
40509 msgEl.slideIn('l', {stopFx:true});
40512 hide : function(msgEl, f){
40513 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
40518 * Ext JS Library 1.1.1
40519 * Copyright(c) 2006-2007, Ext JS, LLC.
40521 * Originally Released Under LGPL - original licence link has changed is not relivant.
40524 * <script type="text/javascript">
40529 * @class Roo.form.TextField
40530 * @extends Roo.form.Field
40531 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
40532 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
40534 * Creates a new TextField
40535 * @param {Object} config Configuration options
40537 Roo.form.TextField = function(config){
40538 Roo.form.TextField.superclass.constructor.call(this, config);
40542 * Fires when the autosize function is triggered. The field may or may not have actually changed size
40543 * according to the default logic, but this event provides a hook for the developer to apply additional
40544 * logic at runtime to resize the field if needed.
40545 * @param {Roo.form.Field} this This text field
40546 * @param {Number} width The new field width
40552 Roo.extend(Roo.form.TextField, Roo.form.Field, {
40554 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
40558 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
40562 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
40566 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
40570 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
40574 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
40576 disableKeyFilter : false,
40578 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
40582 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
40586 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
40588 maxLength : Number.MAX_VALUE,
40590 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
40592 minLengthText : "The minimum length for this field is {0}",
40594 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
40596 maxLengthText : "The maximum length for this field is {0}",
40598 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
40600 selectOnFocus : false,
40602 * @cfg {Boolean} allowLeadingSpace True to prevent the stripping of leading white space
40604 allowLeadingSpace : false,
40606 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
40608 blankText : "This field is required",
40610 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
40611 * If available, this function will be called only after the basic validators all return true, and will be passed the
40612 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
40616 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
40617 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
40618 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
40622 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
40626 * @cfg {String} emptyText The default text to display in an empty field - placeholder... (defaults to null).
40632 initEvents : function()
40634 if (this.emptyText) {
40635 this.el.attr('placeholder', this.emptyText);
40638 Roo.form.TextField.superclass.initEvents.call(this);
40639 if(this.validationEvent == 'keyup'){
40640 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
40641 this.el.on('keyup', this.filterValidation, this);
40643 else if(this.validationEvent !== false){
40644 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
40647 if(this.selectOnFocus){
40648 this.on("focus", this.preFocus, this);
40650 if (!this.allowLeadingSpace) {
40651 this.on('blur', this.cleanLeadingSpace, this);
40654 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
40655 this.el.on("keypress", this.filterKeys, this);
40658 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
40659 this.el.on("click", this.autoSize, this);
40661 if(this.el.is('input[type=password]') && Roo.isSafari){
40662 this.el.on('keydown', this.SafariOnKeyDown, this);
40666 processValue : function(value){
40667 if(this.stripCharsRe){
40668 var newValue = value.replace(this.stripCharsRe, '');
40669 if(newValue !== value){
40670 this.setRawValue(newValue);
40677 filterValidation : function(e){
40678 if(!e.isNavKeyPress()){
40679 this.validationTask.delay(this.validationDelay);
40684 onKeyUp : function(e){
40685 if(!e.isNavKeyPress()){
40689 // private - clean the leading white space
40690 cleanLeadingSpace : function(e)
40692 if ( this.inputType == 'file') {
40696 this.setValue((this.getValue() + '').replace(/^\s+/,''));
40699 * Resets the current field value to the originally-loaded value and clears any validation messages.
40702 reset : function(){
40703 Roo.form.TextField.superclass.reset.call(this);
40707 preFocus : function(){
40709 if(this.selectOnFocus){
40710 this.el.dom.select();
40716 filterKeys : function(e){
40717 var k = e.getKey();
40718 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
40721 var c = e.getCharCode(), cc = String.fromCharCode(c);
40722 if(Roo.isIE && (e.isSpecialKey() || !cc)){
40725 if(!this.maskRe.test(cc)){
40730 setValue : function(v){
40732 Roo.form.TextField.superclass.setValue.apply(this, arguments);
40738 * Validates a value according to the field's validation rules and marks the field as invalid
40739 * if the validation fails
40740 * @param {Mixed} value The value to validate
40741 * @return {Boolean} True if the value is valid, else false
40743 validateValue : function(value){
40744 if(value.length < 1) { // if it's blank
40745 if(this.allowBlank){
40746 this.clearInvalid();
40749 this.markInvalid(this.blankText);
40753 if(value.length < this.minLength){
40754 this.markInvalid(String.format(this.minLengthText, this.minLength));
40757 if(value.length > this.maxLength){
40758 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
40762 var vt = Roo.form.VTypes;
40763 if(!vt[this.vtype](value, this)){
40764 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
40768 if(typeof this.validator == "function"){
40769 var msg = this.validator(value);
40771 this.markInvalid(msg);
40775 if(this.regex && !this.regex.test(value)){
40776 this.markInvalid(this.regexText);
40783 * Selects text in this field
40784 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
40785 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
40787 selectText : function(start, end){
40788 var v = this.getRawValue();
40790 start = start === undefined ? 0 : start;
40791 end = end === undefined ? v.length : end;
40792 var d = this.el.dom;
40793 if(d.setSelectionRange){
40794 d.setSelectionRange(start, end);
40795 }else if(d.createTextRange){
40796 var range = d.createTextRange();
40797 range.moveStart("character", start);
40798 range.moveEnd("character", v.length-end);
40805 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
40806 * This only takes effect if grow = true, and fires the autosize event.
40808 autoSize : function(){
40809 if(!this.grow || !this.rendered){
40813 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
40816 var v = el.dom.value;
40817 var d = document.createElement('div');
40818 d.appendChild(document.createTextNode(v));
40822 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
40823 this.el.setWidth(w);
40824 this.fireEvent("autosize", this, w);
40828 SafariOnKeyDown : function(event)
40830 // this is a workaround for a password hang bug on chrome/ webkit.
40832 var isSelectAll = false;
40834 if(this.el.dom.selectionEnd > 0){
40835 isSelectAll = (this.el.dom.selectionEnd - this.el.dom.selectionStart - this.getValue().length == 0) ? true : false;
40837 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
40838 event.preventDefault();
40843 if(isSelectAll && event.getCharCode() > 31){ // backspace and delete key
40845 event.preventDefault();
40846 // this is very hacky as keydown always get's upper case.
40848 var cc = String.fromCharCode(event.getCharCode());
40851 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
40859 * Ext JS Library 1.1.1
40860 * Copyright(c) 2006-2007, Ext JS, LLC.
40862 * Originally Released Under LGPL - original licence link has changed is not relivant.
40865 * <script type="text/javascript">
40869 * @class Roo.form.Hidden
40870 * @extends Roo.form.TextField
40871 * Simple Hidden element used on forms
40873 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
40876 * Creates a new Hidden form element.
40877 * @param {Object} config Configuration options
40882 // easy hidden field...
40883 Roo.form.Hidden = function(config){
40884 Roo.form.Hidden.superclass.constructor.call(this, config);
40887 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
40889 inputType: 'hidden',
40892 labelSeparator: '',
40894 itemCls : 'x-form-item-display-none'
40902 * Ext JS Library 1.1.1
40903 * Copyright(c) 2006-2007, Ext JS, LLC.
40905 * Originally Released Under LGPL - original licence link has changed is not relivant.
40908 * <script type="text/javascript">
40912 * @class Roo.form.TriggerField
40913 * @extends Roo.form.TextField
40914 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
40915 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
40916 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
40917 * for which you can provide a custom implementation. For example:
40919 var trigger = new Roo.form.TriggerField();
40920 trigger.onTriggerClick = myTriggerFn;
40921 trigger.applyTo('my-field');
40924 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
40925 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
40926 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
40927 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
40929 * Create a new TriggerField.
40930 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
40931 * to the base TextField)
40933 Roo.form.TriggerField = function(config){
40934 this.mimicing = false;
40935 Roo.form.TriggerField.superclass.constructor.call(this, config);
40938 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
40940 * @cfg {String} triggerClass A CSS class to apply to the trigger
40943 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
40944 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
40946 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "new-password"},
40948 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
40952 /** @cfg {Boolean} grow @hide */
40953 /** @cfg {Number} growMin @hide */
40954 /** @cfg {Number} growMax @hide */
40960 autoSize: Roo.emptyFn,
40964 deferHeight : true,
40967 actionMode : 'wrap',
40969 onResize : function(w, h){
40970 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
40971 if(typeof w == 'number'){
40972 var x = w - this.trigger.getWidth();
40973 this.el.setWidth(this.adjustWidth('input', x));
40974 this.trigger.setStyle('left', x+'px');
40979 adjustSize : Roo.BoxComponent.prototype.adjustSize,
40982 getResizeEl : function(){
40987 getPositionEl : function(){
40992 alignErrorIcon : function(){
40993 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
40997 onRender : function(ct, position){
40998 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
40999 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
41000 this.trigger = this.wrap.createChild(this.triggerConfig ||
41001 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
41002 if(this.hideTrigger){
41003 this.trigger.setDisplayed(false);
41005 this.initTrigger();
41007 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
41012 initTrigger : function(){
41013 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
41014 this.trigger.addClassOnOver('x-form-trigger-over');
41015 this.trigger.addClassOnClick('x-form-trigger-click');
41019 onDestroy : function(){
41021 this.trigger.removeAllListeners();
41022 this.trigger.remove();
41025 this.wrap.remove();
41027 Roo.form.TriggerField.superclass.onDestroy.call(this);
41031 onFocus : function(){
41032 Roo.form.TriggerField.superclass.onFocus.call(this);
41033 if(!this.mimicing){
41034 this.wrap.addClass('x-trigger-wrap-focus');
41035 this.mimicing = true;
41036 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
41037 if(this.monitorTab){
41038 this.el.on("keydown", this.checkTab, this);
41044 checkTab : function(e){
41045 if(e.getKey() == e.TAB){
41046 this.triggerBlur();
41051 onBlur : function(){
41056 mimicBlur : function(e, t){
41057 if(!this.wrap.contains(t) && this.validateBlur()){
41058 this.triggerBlur();
41063 triggerBlur : function(){
41064 this.mimicing = false;
41065 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
41066 if(this.monitorTab){
41067 this.el.un("keydown", this.checkTab, this);
41069 this.wrap.removeClass('x-trigger-wrap-focus');
41070 Roo.form.TriggerField.superclass.onBlur.call(this);
41074 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
41075 validateBlur : function(e, t){
41080 onDisable : function(){
41081 Roo.form.TriggerField.superclass.onDisable.call(this);
41083 this.wrap.addClass('x-item-disabled');
41088 onEnable : function(){
41089 Roo.form.TriggerField.superclass.onEnable.call(this);
41091 this.wrap.removeClass('x-item-disabled');
41096 onShow : function(){
41097 var ae = this.getActionEl();
41100 ae.dom.style.display = '';
41101 ae.dom.style.visibility = 'visible';
41107 onHide : function(){
41108 var ae = this.getActionEl();
41109 ae.dom.style.display = 'none';
41113 * The function that should handle the trigger's click event. This method does nothing by default until overridden
41114 * by an implementing function.
41116 * @param {EventObject} e
41118 onTriggerClick : Roo.emptyFn
41121 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
41122 // to be extended by an implementing class. For an example of implementing this class, see the custom
41123 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
41124 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
41125 initComponent : function(){
41126 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
41128 this.triggerConfig = {
41129 tag:'span', cls:'x-form-twin-triggers', cn:[
41130 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
41131 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
41135 getTrigger : function(index){
41136 return this.triggers[index];
41139 initTrigger : function(){
41140 var ts = this.trigger.select('.x-form-trigger', true);
41141 this.wrap.setStyle('overflow', 'hidden');
41142 var triggerField = this;
41143 ts.each(function(t, all, index){
41144 t.hide = function(){
41145 var w = triggerField.wrap.getWidth();
41146 this.dom.style.display = 'none';
41147 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
41149 t.show = function(){
41150 var w = triggerField.wrap.getWidth();
41151 this.dom.style.display = '';
41152 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
41154 var triggerIndex = 'Trigger'+(index+1);
41156 if(this['hide'+triggerIndex]){
41157 t.dom.style.display = 'none';
41159 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
41160 t.addClassOnOver('x-form-trigger-over');
41161 t.addClassOnClick('x-form-trigger-click');
41163 this.triggers = ts.elements;
41166 onTrigger1Click : Roo.emptyFn,
41167 onTrigger2Click : Roo.emptyFn
41170 * Ext JS Library 1.1.1
41171 * Copyright(c) 2006-2007, Ext JS, LLC.
41173 * Originally Released Under LGPL - original licence link has changed is not relivant.
41176 * <script type="text/javascript">
41180 * @class Roo.form.TextArea
41181 * @extends Roo.form.TextField
41182 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
41183 * support for auto-sizing.
41185 * Creates a new TextArea
41186 * @param {Object} config Configuration options
41188 Roo.form.TextArea = function(config){
41189 Roo.form.TextArea.superclass.constructor.call(this, config);
41190 // these are provided exchanges for backwards compat
41191 // minHeight/maxHeight were replaced by growMin/growMax to be
41192 // compatible with TextField growing config values
41193 if(this.minHeight !== undefined){
41194 this.growMin = this.minHeight;
41196 if(this.maxHeight !== undefined){
41197 this.growMax = this.maxHeight;
41201 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
41203 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
41207 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
41211 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
41212 * in the field (equivalent to setting overflow: hidden, defaults to false)
41214 preventScrollbars: false,
41216 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
41217 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
41221 onRender : function(ct, position){
41223 this.defaultAutoCreate = {
41225 style:"width:300px;height:60px;",
41226 autocomplete: "new-password"
41229 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
41231 this.textSizeEl = Roo.DomHelper.append(document.body, {
41232 tag: "pre", cls: "x-form-grow-sizer"
41234 if(this.preventScrollbars){
41235 this.el.setStyle("overflow", "hidden");
41237 this.el.setHeight(this.growMin);
41241 onDestroy : function(){
41242 if(this.textSizeEl){
41243 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
41245 Roo.form.TextArea.superclass.onDestroy.call(this);
41249 onKeyUp : function(e){
41250 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
41256 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
41257 * This only takes effect if grow = true, and fires the autosize event if the height changes.
41259 autoSize : function(){
41260 if(!this.grow || !this.textSizeEl){
41264 var v = el.dom.value;
41265 var ts = this.textSizeEl;
41268 ts.appendChild(document.createTextNode(v));
41271 Roo.fly(ts).setWidth(this.el.getWidth());
41273 v = "  ";
41276 v = v.replace(/\n/g, '<p> </p>');
41278 v += " \n ";
41281 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
41282 if(h != this.lastHeight){
41283 this.lastHeight = h;
41284 this.el.setHeight(h);
41285 this.fireEvent("autosize", this, h);
41290 * Ext JS Library 1.1.1
41291 * Copyright(c) 2006-2007, Ext JS, LLC.
41293 * Originally Released Under LGPL - original licence link has changed is not relivant.
41296 * <script type="text/javascript">
41301 * @class Roo.form.NumberField
41302 * @extends Roo.form.TextField
41303 * Numeric text field that provides automatic keystroke filtering and numeric validation.
41305 * Creates a new NumberField
41306 * @param {Object} config Configuration options
41308 Roo.form.NumberField = function(config){
41309 Roo.form.NumberField.superclass.constructor.call(this, config);
41312 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
41314 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
41316 fieldClass: "x-form-field x-form-num-field",
41318 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
41320 allowDecimals : true,
41322 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
41324 decimalSeparator : ".",
41326 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
41328 decimalPrecision : 2,
41330 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
41332 allowNegative : true,
41334 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
41336 minValue : Number.NEGATIVE_INFINITY,
41338 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
41340 maxValue : Number.MAX_VALUE,
41342 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
41344 minText : "The minimum value for this field is {0}",
41346 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
41348 maxText : "The maximum value for this field is {0}",
41350 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
41351 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
41353 nanText : "{0} is not a valid number",
41356 initEvents : function(){
41357 Roo.form.NumberField.superclass.initEvents.call(this);
41358 var allowed = "0123456789";
41359 if(this.allowDecimals){
41360 allowed += this.decimalSeparator;
41362 if(this.allowNegative){
41365 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
41366 var keyPress = function(e){
41367 var k = e.getKey();
41368 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
41371 var c = e.getCharCode();
41372 if(allowed.indexOf(String.fromCharCode(c)) === -1){
41376 this.el.on("keypress", keyPress, this);
41380 validateValue : function(value){
41381 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
41384 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
41387 var num = this.parseValue(value);
41389 this.markInvalid(String.format(this.nanText, value));
41392 if(num < this.minValue){
41393 this.markInvalid(String.format(this.minText, this.minValue));
41396 if(num > this.maxValue){
41397 this.markInvalid(String.format(this.maxText, this.maxValue));
41403 getValue : function(){
41404 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
41408 parseValue : function(value){
41409 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
41410 return isNaN(value) ? '' : value;
41414 fixPrecision : function(value){
41415 var nan = isNaN(value);
41416 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
41417 return nan ? '' : value;
41419 return parseFloat(value).toFixed(this.decimalPrecision);
41422 setValue : function(v){
41423 v = this.fixPrecision(v);
41424 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
41428 decimalPrecisionFcn : function(v){
41429 return Math.floor(v);
41432 beforeBlur : function(){
41433 var v = this.parseValue(this.getRawValue());
41440 * Ext JS Library 1.1.1
41441 * Copyright(c) 2006-2007, Ext JS, LLC.
41443 * Originally Released Under LGPL - original licence link has changed is not relivant.
41446 * <script type="text/javascript">
41450 * @class Roo.form.DateField
41451 * @extends Roo.form.TriggerField
41452 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
41454 * Create a new DateField
41455 * @param {Object} config
41457 Roo.form.DateField = function(config)
41459 Roo.form.DateField.superclass.constructor.call(this, config);
41465 * Fires when a date is selected
41466 * @param {Roo.form.DateField} combo This combo box
41467 * @param {Date} date The date selected
41474 if(typeof this.minValue == "string") {
41475 this.minValue = this.parseDate(this.minValue);
41477 if(typeof this.maxValue == "string") {
41478 this.maxValue = this.parseDate(this.maxValue);
41480 this.ddMatch = null;
41481 if(this.disabledDates){
41482 var dd = this.disabledDates;
41484 for(var i = 0; i < dd.length; i++){
41486 if(i != dd.length-1) {
41490 this.ddMatch = new RegExp(re + ")");
41494 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
41496 * @cfg {String} format
41497 * The default date format string which can be overriden for localization support. The format must be
41498 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
41502 * @cfg {String} altFormats
41503 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
41504 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
41506 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
41508 * @cfg {Array} disabledDays
41509 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
41511 disabledDays : null,
41513 * @cfg {String} disabledDaysText
41514 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
41516 disabledDaysText : "Disabled",
41518 * @cfg {Array} disabledDates
41519 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
41520 * expression so they are very powerful. Some examples:
41522 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
41523 * <li>["03/08", "09/16"] would disable those days for every year</li>
41524 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
41525 * <li>["03/../2006"] would disable every day in March 2006</li>
41526 * <li>["^03"] would disable every day in every March</li>
41528 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
41529 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
41531 disabledDates : null,
41533 * @cfg {String} disabledDatesText
41534 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
41536 disabledDatesText : "Disabled",
41538 * @cfg {Date/String} minValue
41539 * The minimum allowed date. Can be either a Javascript date object or a string date in a
41540 * valid format (defaults to null).
41544 * @cfg {Date/String} maxValue
41545 * The maximum allowed date. Can be either a Javascript date object or a string date in a
41546 * valid format (defaults to null).
41550 * @cfg {String} minText
41551 * The error text to display when the date in the cell is before minValue (defaults to
41552 * 'The date in this field must be after {minValue}').
41554 minText : "The date in this field must be equal to or after {0}",
41556 * @cfg {String} maxText
41557 * The error text to display when the date in the cell is after maxValue (defaults to
41558 * 'The date in this field must be before {maxValue}').
41560 maxText : "The date in this field must be equal to or before {0}",
41562 * @cfg {String} invalidText
41563 * The error text to display when the date in the field is invalid (defaults to
41564 * '{value} is not a valid date - it must be in the format {format}').
41566 invalidText : "{0} is not a valid date - it must be in the format {1}",
41568 * @cfg {String} triggerClass
41569 * An additional CSS class used to style the trigger button. The trigger will always get the
41570 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
41571 * which displays a calendar icon).
41573 triggerClass : 'x-form-date-trigger',
41577 * @cfg {Boolean} useIso
41578 * if enabled, then the date field will use a hidden field to store the
41579 * real value as iso formated date. default (false)
41583 * @cfg {String/Object} autoCreate
41584 * A DomHelper element spec, or true for a default element spec (defaults to
41585 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
41588 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
41591 hiddenField: false,
41593 onRender : function(ct, position)
41595 Roo.form.DateField.superclass.onRender.call(this, ct, position);
41597 //this.el.dom.removeAttribute('name');
41598 Roo.log("Changing name?");
41599 this.el.dom.setAttribute('name', this.name + '____hidden___' );
41600 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
41602 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
41603 // prevent input submission
41604 this.hiddenName = this.name;
41611 validateValue : function(value)
41613 value = this.formatDate(value);
41614 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
41615 Roo.log('super failed');
41618 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
41621 var svalue = value;
41622 value = this.parseDate(value);
41624 Roo.log('parse date failed' + svalue);
41625 this.markInvalid(String.format(this.invalidText, svalue, this.format));
41628 var time = value.getTime();
41629 if(this.minValue && time < this.minValue.getTime()){
41630 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
41633 if(this.maxValue && time > this.maxValue.getTime()){
41634 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
41637 if(this.disabledDays){
41638 var day = value.getDay();
41639 for(var i = 0; i < this.disabledDays.length; i++) {
41640 if(day === this.disabledDays[i]){
41641 this.markInvalid(this.disabledDaysText);
41646 var fvalue = this.formatDate(value);
41647 if(this.ddMatch && this.ddMatch.test(fvalue)){
41648 this.markInvalid(String.format(this.disabledDatesText, fvalue));
41655 // Provides logic to override the default TriggerField.validateBlur which just returns true
41656 validateBlur : function(){
41657 return !this.menu || !this.menu.isVisible();
41660 getName: function()
41662 // returns hidden if it's set..
41663 if (!this.rendered) {return ''};
41664 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
41669 * Returns the current date value of the date field.
41670 * @return {Date} The date value
41672 getValue : function(){
41674 return this.hiddenField ?
41675 this.hiddenField.value :
41676 this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
41680 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
41681 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
41682 * (the default format used is "m/d/y").
41685 //All of these calls set the same date value (May 4, 2006)
41687 //Pass a date object:
41688 var dt = new Date('5/4/06');
41689 dateField.setValue(dt);
41691 //Pass a date string (default format):
41692 dateField.setValue('5/4/06');
41694 //Pass a date string (custom format):
41695 dateField.format = 'Y-m-d';
41696 dateField.setValue('2006-5-4');
41698 * @param {String/Date} date The date or valid date string
41700 setValue : function(date){
41701 if (this.hiddenField) {
41702 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
41704 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
41705 // make sure the value field is always stored as a date..
41706 this.value = this.parseDate(date);
41712 parseDate : function(value){
41713 if(!value || value instanceof Date){
41716 var v = Date.parseDate(value, this.format);
41717 if (!v && this.useIso) {
41718 v = Date.parseDate(value, 'Y-m-d');
41720 if(!v && this.altFormats){
41721 if(!this.altFormatsArray){
41722 this.altFormatsArray = this.altFormats.split("|");
41724 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
41725 v = Date.parseDate(value, this.altFormatsArray[i]);
41732 formatDate : function(date, fmt){
41733 return (!date || !(date instanceof Date)) ?
41734 date : date.dateFormat(fmt || this.format);
41739 select: function(m, d){
41742 this.fireEvent('select', this, d);
41744 show : function(){ // retain focus styling
41748 this.focus.defer(10, this);
41749 var ml = this.menuListeners;
41750 this.menu.un("select", ml.select, this);
41751 this.menu.un("show", ml.show, this);
41752 this.menu.un("hide", ml.hide, this);
41757 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
41758 onTriggerClick : function(){
41762 if(this.menu == null){
41763 this.menu = new Roo.menu.DateMenu();
41765 Roo.apply(this.menu.picker, {
41766 showClear: this.allowBlank,
41767 minDate : this.minValue,
41768 maxDate : this.maxValue,
41769 disabledDatesRE : this.ddMatch,
41770 disabledDatesText : this.disabledDatesText,
41771 disabledDays : this.disabledDays,
41772 disabledDaysText : this.disabledDaysText,
41773 format : this.useIso ? 'Y-m-d' : this.format,
41774 minText : String.format(this.minText, this.formatDate(this.minValue)),
41775 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
41777 this.menu.on(Roo.apply({}, this.menuListeners, {
41780 this.menu.picker.setValue(this.getValue() || new Date());
41781 this.menu.show(this.el, "tl-bl?");
41784 beforeBlur : function(){
41785 var v = this.parseDate(this.getRawValue());
41795 isDirty : function() {
41796 if(this.disabled) {
41800 if(typeof(this.startValue) === 'undefined'){
41804 return String(this.getValue()) !== String(this.startValue);
41808 cleanLeadingSpace : function(e)
41815 * Ext JS Library 1.1.1
41816 * Copyright(c) 2006-2007, Ext JS, LLC.
41818 * Originally Released Under LGPL - original licence link has changed is not relivant.
41821 * <script type="text/javascript">
41825 * @class Roo.form.MonthField
41826 * @extends Roo.form.TriggerField
41827 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
41829 * Create a new MonthField
41830 * @param {Object} config
41832 Roo.form.MonthField = function(config){
41834 Roo.form.MonthField.superclass.constructor.call(this, config);
41840 * Fires when a date is selected
41841 * @param {Roo.form.MonthFieeld} combo This combo box
41842 * @param {Date} date The date selected
41849 if(typeof this.minValue == "string") {
41850 this.minValue = this.parseDate(this.minValue);
41852 if(typeof this.maxValue == "string") {
41853 this.maxValue = this.parseDate(this.maxValue);
41855 this.ddMatch = null;
41856 if(this.disabledDates){
41857 var dd = this.disabledDates;
41859 for(var i = 0; i < dd.length; i++){
41861 if(i != dd.length-1) {
41865 this.ddMatch = new RegExp(re + ")");
41869 Roo.extend(Roo.form.MonthField, Roo.form.TriggerField, {
41871 * @cfg {String} format
41872 * The default date format string which can be overriden for localization support. The format must be
41873 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
41877 * @cfg {String} altFormats
41878 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
41879 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
41881 altFormats : "M Y|m/Y|m-y|m-Y|my|mY",
41883 * @cfg {Array} disabledDays
41884 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
41886 disabledDays : [0,1,2,3,4,5,6],
41888 * @cfg {String} disabledDaysText
41889 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
41891 disabledDaysText : "Disabled",
41893 * @cfg {Array} disabledDates
41894 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
41895 * expression so they are very powerful. Some examples:
41897 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
41898 * <li>["03/08", "09/16"] would disable those days for every year</li>
41899 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
41900 * <li>["03/../2006"] would disable every day in March 2006</li>
41901 * <li>["^03"] would disable every day in every March</li>
41903 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
41904 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
41906 disabledDates : null,
41908 * @cfg {String} disabledDatesText
41909 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
41911 disabledDatesText : "Disabled",
41913 * @cfg {Date/String} minValue
41914 * The minimum allowed date. Can be either a Javascript date object or a string date in a
41915 * valid format (defaults to null).
41919 * @cfg {Date/String} maxValue
41920 * The maximum allowed date. Can be either a Javascript date object or a string date in a
41921 * valid format (defaults to null).
41925 * @cfg {String} minText
41926 * The error text to display when the date in the cell is before minValue (defaults to
41927 * 'The date in this field must be after {minValue}').
41929 minText : "The date in this field must be equal to or after {0}",
41931 * @cfg {String} maxTextf
41932 * The error text to display when the date in the cell is after maxValue (defaults to
41933 * 'The date in this field must be before {maxValue}').
41935 maxText : "The date in this field must be equal to or before {0}",
41937 * @cfg {String} invalidText
41938 * The error text to display when the date in the field is invalid (defaults to
41939 * '{value} is not a valid date - it must be in the format {format}').
41941 invalidText : "{0} is not a valid date - it must be in the format {1}",
41943 * @cfg {String} triggerClass
41944 * An additional CSS class used to style the trigger button. The trigger will always get the
41945 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
41946 * which displays a calendar icon).
41948 triggerClass : 'x-form-date-trigger',
41952 * @cfg {Boolean} useIso
41953 * if enabled, then the date field will use a hidden field to store the
41954 * real value as iso formated date. default (true)
41958 * @cfg {String/Object} autoCreate
41959 * A DomHelper element spec, or true for a default element spec (defaults to
41960 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
41963 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "new-password"},
41966 hiddenField: false,
41968 hideMonthPicker : false,
41970 onRender : function(ct, position)
41972 Roo.form.MonthField.superclass.onRender.call(this, ct, position);
41974 this.el.dom.removeAttribute('name');
41975 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
41977 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
41978 // prevent input submission
41979 this.hiddenName = this.name;
41986 validateValue : function(value)
41988 value = this.formatDate(value);
41989 if(!Roo.form.MonthField.superclass.validateValue.call(this, value)){
41992 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
41995 var svalue = value;
41996 value = this.parseDate(value);
41998 this.markInvalid(String.format(this.invalidText, svalue, this.format));
42001 var time = value.getTime();
42002 if(this.minValue && time < this.minValue.getTime()){
42003 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
42006 if(this.maxValue && time > this.maxValue.getTime()){
42007 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
42010 /*if(this.disabledDays){
42011 var day = value.getDay();
42012 for(var i = 0; i < this.disabledDays.length; i++) {
42013 if(day === this.disabledDays[i]){
42014 this.markInvalid(this.disabledDaysText);
42020 var fvalue = this.formatDate(value);
42021 /*if(this.ddMatch && this.ddMatch.test(fvalue)){
42022 this.markInvalid(String.format(this.disabledDatesText, fvalue));
42030 // Provides logic to override the default TriggerField.validateBlur which just returns true
42031 validateBlur : function(){
42032 return !this.menu || !this.menu.isVisible();
42036 * Returns the current date value of the date field.
42037 * @return {Date} The date value
42039 getValue : function(){
42043 return this.hiddenField ?
42044 this.hiddenField.value :
42045 this.parseDate(Roo.form.MonthField.superclass.getValue.call(this)) || "";
42049 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
42050 * date, using MonthField.format as the date format, according to the same rules as {@link Date#parseDate}
42051 * (the default format used is "m/d/y").
42054 //All of these calls set the same date value (May 4, 2006)
42056 //Pass a date object:
42057 var dt = new Date('5/4/06');
42058 monthField.setValue(dt);
42060 //Pass a date string (default format):
42061 monthField.setValue('5/4/06');
42063 //Pass a date string (custom format):
42064 monthField.format = 'Y-m-d';
42065 monthField.setValue('2006-5-4');
42067 * @param {String/Date} date The date or valid date string
42069 setValue : function(date){
42070 Roo.log('month setValue' + date);
42071 // can only be first of month..
42073 var val = this.parseDate(date);
42075 if (this.hiddenField) {
42076 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
42078 Roo.form.MonthField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
42079 this.value = this.parseDate(date);
42083 parseDate : function(value){
42084 if(!value || value instanceof Date){
42085 value = value ? Date.parseDate(value.format('Y-m') + '-01', 'Y-m-d') : null;
42088 var v = Date.parseDate(value, this.format);
42089 if (!v && this.useIso) {
42090 v = Date.parseDate(value, 'Y-m-d');
42094 v = Date.parseDate(v.format('Y-m') +'-01', 'Y-m-d');
42098 if(!v && this.altFormats){
42099 if(!this.altFormatsArray){
42100 this.altFormatsArray = this.altFormats.split("|");
42102 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
42103 v = Date.parseDate(value, this.altFormatsArray[i]);
42110 formatDate : function(date, fmt){
42111 return (!date || !(date instanceof Date)) ?
42112 date : date.dateFormat(fmt || this.format);
42117 select: function(m, d){
42119 this.fireEvent('select', this, d);
42121 show : function(){ // retain focus styling
42125 this.focus.defer(10, this);
42126 var ml = this.menuListeners;
42127 this.menu.un("select", ml.select, this);
42128 this.menu.un("show", ml.show, this);
42129 this.menu.un("hide", ml.hide, this);
42133 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
42134 onTriggerClick : function(){
42138 if(this.menu == null){
42139 this.menu = new Roo.menu.DateMenu();
42143 Roo.apply(this.menu.picker, {
42145 showClear: this.allowBlank,
42146 minDate : this.minValue,
42147 maxDate : this.maxValue,
42148 disabledDatesRE : this.ddMatch,
42149 disabledDatesText : this.disabledDatesText,
42151 format : this.useIso ? 'Y-m-d' : this.format,
42152 minText : String.format(this.minText, this.formatDate(this.minValue)),
42153 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
42156 this.menu.on(Roo.apply({}, this.menuListeners, {
42164 // hide month picker get's called when we called by 'before hide';
42166 var ignorehide = true;
42167 p.hideMonthPicker = function(disableAnim){
42171 if(this.monthPicker){
42172 Roo.log("hideMonthPicker called");
42173 if(disableAnim === true){
42174 this.monthPicker.hide();
42176 this.monthPicker.slideOut('t', {duration:.2});
42177 p.setValue(new Date(m.picker.mpSelYear, m.picker.mpSelMonth, 1));
42178 p.fireEvent("select", this, this.value);
42184 Roo.log('picker set value');
42185 Roo.log(this.getValue());
42186 p.setValue(this.getValue() ? this.parseDate(this.getValue()) : new Date());
42187 m.show(this.el, 'tl-bl?');
42188 ignorehide = false;
42189 // this will trigger hideMonthPicker..
42192 // hidden the day picker
42193 Roo.select('.x-date-picker table', true).first().dom.style.visibility = "hidden";
42199 p.showMonthPicker.defer(100, p);
42205 beforeBlur : function(){
42206 var v = this.parseDate(this.getRawValue());
42212 /** @cfg {Boolean} grow @hide */
42213 /** @cfg {Number} growMin @hide */
42214 /** @cfg {Number} growMax @hide */
42221 * Ext JS Library 1.1.1
42222 * Copyright(c) 2006-2007, Ext JS, LLC.
42224 * Originally Released Under LGPL - original licence link has changed is not relivant.
42227 * <script type="text/javascript">
42232 * @class Roo.form.ComboBox
42233 * @extends Roo.form.TriggerField
42234 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
42236 * Create a new ComboBox.
42237 * @param {Object} config Configuration options
42239 Roo.form.ComboBox = function(config){
42240 Roo.form.ComboBox.superclass.constructor.call(this, config);
42244 * Fires when the dropdown list is expanded
42245 * @param {Roo.form.ComboBox} combo This combo box
42250 * Fires when the dropdown list is collapsed
42251 * @param {Roo.form.ComboBox} combo This combo box
42255 * @event beforeselect
42256 * Fires before a list item is selected. Return false to cancel the selection.
42257 * @param {Roo.form.ComboBox} combo This combo box
42258 * @param {Roo.data.Record} record The data record returned from the underlying store
42259 * @param {Number} index The index of the selected item in the dropdown list
42261 'beforeselect' : true,
42264 * Fires when a list item is selected
42265 * @param {Roo.form.ComboBox} combo This combo box
42266 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
42267 * @param {Number} index The index of the selected item in the dropdown list
42271 * @event beforequery
42272 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
42273 * The event object passed has these properties:
42274 * @param {Roo.form.ComboBox} combo This combo box
42275 * @param {String} query The query
42276 * @param {Boolean} forceAll true to force "all" query
42277 * @param {Boolean} cancel true to cancel the query
42278 * @param {Object} e The query event object
42280 'beforequery': true,
42283 * Fires when the 'add' icon is pressed (add a listener to enable add button)
42284 * @param {Roo.form.ComboBox} combo This combo box
42289 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
42290 * @param {Roo.form.ComboBox} combo This combo box
42291 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
42297 if(this.transform){
42298 this.allowDomMove = false;
42299 var s = Roo.getDom(this.transform);
42300 if(!this.hiddenName){
42301 this.hiddenName = s.name;
42304 this.mode = 'local';
42305 var d = [], opts = s.options;
42306 for(var i = 0, len = opts.length;i < len; i++){
42308 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
42310 this.value = value;
42312 d.push([value, o.text]);
42314 this.store = new Roo.data.SimpleStore({
42316 fields: ['value', 'text'],
42319 this.valueField = 'value';
42320 this.displayField = 'text';
42322 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
42323 if(!this.lazyRender){
42324 this.target = true;
42325 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
42326 s.parentNode.removeChild(s); // remove it
42327 this.render(this.el.parentNode);
42329 s.parentNode.removeChild(s); // remove it
42334 this.store = Roo.factory(this.store, Roo.data);
42337 this.selectedIndex = -1;
42338 if(this.mode == 'local'){
42339 if(config.queryDelay === undefined){
42340 this.queryDelay = 10;
42342 if(config.minChars === undefined){
42348 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
42350 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
42353 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
42354 * rendering into an Roo.Editor, defaults to false)
42357 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
42358 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
42361 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
42364 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
42365 * the dropdown list (defaults to undefined, with no header element)
42369 * @cfg {String/Roo.Template} tpl The template to use to render the output
42373 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
42375 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
42377 listWidth: undefined,
42379 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
42380 * mode = 'remote' or 'text' if mode = 'local')
42382 displayField: undefined,
42384 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
42385 * mode = 'remote' or 'value' if mode = 'local').
42386 * Note: use of a valueField requires the user make a selection
42387 * in order for a value to be mapped.
42389 valueField: undefined,
42393 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
42394 * field's data value (defaults to the underlying DOM element's name)
42396 hiddenName: undefined,
42398 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
42402 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
42404 selectedClass: 'x-combo-selected',
42406 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
42407 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
42408 * which displays a downward arrow icon).
42410 triggerClass : 'x-form-arrow-trigger',
42412 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
42416 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
42417 * anchor positions (defaults to 'tl-bl')
42419 listAlign: 'tl-bl?',
42421 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
42425 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
42426 * query specified by the allQuery config option (defaults to 'query')
42428 triggerAction: 'query',
42430 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
42431 * (defaults to 4, does not apply if editable = false)
42435 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
42436 * delay (typeAheadDelay) if it matches a known value (defaults to false)
42440 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
42441 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
42445 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
42446 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
42450 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
42451 * when editable = true (defaults to false)
42453 selectOnFocus:false,
42455 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
42457 queryParam: 'query',
42459 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
42460 * when mode = 'remote' (defaults to 'Loading...')
42462 loadingText: 'Loading...',
42464 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
42468 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
42472 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
42473 * traditional select (defaults to true)
42477 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
42481 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
42485 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
42486 * listWidth has a higher value)
42490 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
42491 * allow the user to set arbitrary text into the field (defaults to false)
42493 forceSelection:false,
42495 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
42496 * if typeAhead = true (defaults to 250)
42498 typeAheadDelay : 250,
42500 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
42501 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
42503 valueNotFoundText : undefined,
42505 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
42507 blockFocus : false,
42510 * @cfg {Boolean} disableClear Disable showing of clear button.
42512 disableClear : false,
42514 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
42516 alwaysQuery : false,
42522 // element that contains real text value.. (when hidden is used..)
42525 onRender : function(ct, position)
42527 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
42529 if(this.hiddenName){
42530 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
42532 this.hiddenField.value =
42533 this.hiddenValue !== undefined ? this.hiddenValue :
42534 this.value !== undefined ? this.value : '';
42536 // prevent input submission
42537 this.el.dom.removeAttribute('name');
42543 this.el.dom.setAttribute('autocomplete', 'off');
42546 var cls = 'x-combo-list';
42548 this.list = new Roo.Layer({
42549 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
42552 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
42553 this.list.setWidth(lw);
42554 this.list.swallowEvent('mousewheel');
42555 this.assetHeight = 0;
42558 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
42559 this.assetHeight += this.header.getHeight();
42562 this.innerList = this.list.createChild({cls:cls+'-inner'});
42563 this.innerList.on('mouseover', this.onViewOver, this);
42564 this.innerList.on('mousemove', this.onViewMove, this);
42565 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
42567 if(this.allowBlank && !this.pageSize && !this.disableClear){
42568 this.footer = this.list.createChild({cls:cls+'-ft'});
42569 this.pageTb = new Roo.Toolbar(this.footer);
42573 this.footer = this.list.createChild({cls:cls+'-ft'});
42574 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
42575 {pageSize: this.pageSize});
42579 if (this.pageTb && this.allowBlank && !this.disableClear) {
42581 this.pageTb.add(new Roo.Toolbar.Fill(), {
42582 cls: 'x-btn-icon x-btn-clear',
42584 handler: function()
42587 _this.clearValue();
42588 _this.onSelect(false, -1);
42593 this.assetHeight += this.footer.getHeight();
42598 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
42601 this.view = new Roo.View(this.innerList, this.tpl, {
42604 selectedClass: this.selectedClass
42607 this.view.on('click', this.onViewClick, this);
42609 this.store.on('beforeload', this.onBeforeLoad, this);
42610 this.store.on('load', this.onLoad, this);
42611 this.store.on('loadexception', this.onLoadException, this);
42613 if(this.resizable){
42614 this.resizer = new Roo.Resizable(this.list, {
42615 pinned:true, handles:'se'
42617 this.resizer.on('resize', function(r, w, h){
42618 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
42619 this.listWidth = w;
42620 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
42621 this.restrictHeight();
42623 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
42625 if(!this.editable){
42626 this.editable = true;
42627 this.setEditable(false);
42631 if (typeof(this.events.add.listeners) != 'undefined') {
42633 this.addicon = this.wrap.createChild(
42634 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
42636 this.addicon.on('click', function(e) {
42637 this.fireEvent('add', this);
42640 if (typeof(this.events.edit.listeners) != 'undefined') {
42642 this.editicon = this.wrap.createChild(
42643 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
42644 if (this.addicon) {
42645 this.editicon.setStyle('margin-left', '40px');
42647 this.editicon.on('click', function(e) {
42649 // we fire even if inothing is selected..
42650 this.fireEvent('edit', this, this.lastData );
42660 initEvents : function(){
42661 Roo.form.ComboBox.superclass.initEvents.call(this);
42663 this.keyNav = new Roo.KeyNav(this.el, {
42664 "up" : function(e){
42665 this.inKeyMode = true;
42669 "down" : function(e){
42670 if(!this.isExpanded()){
42671 this.onTriggerClick();
42673 this.inKeyMode = true;
42678 "enter" : function(e){
42679 this.onViewClick();
42683 "esc" : function(e){
42687 "tab" : function(e){
42688 this.onViewClick(false);
42689 this.fireEvent("specialkey", this, e);
42695 doRelay : function(foo, bar, hname){
42696 if(hname == 'down' || this.scope.isExpanded()){
42697 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
42704 this.queryDelay = Math.max(this.queryDelay || 10,
42705 this.mode == 'local' ? 10 : 250);
42706 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
42707 if(this.typeAhead){
42708 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
42710 if(this.editable !== false){
42711 this.el.on("keyup", this.onKeyUp, this);
42713 if(this.forceSelection){
42714 this.on('blur', this.doForce, this);
42718 onDestroy : function(){
42720 this.view.setStore(null);
42721 this.view.el.removeAllListeners();
42722 this.view.el.remove();
42723 this.view.purgeListeners();
42726 this.list.destroy();
42729 this.store.un('beforeload', this.onBeforeLoad, this);
42730 this.store.un('load', this.onLoad, this);
42731 this.store.un('loadexception', this.onLoadException, this);
42733 Roo.form.ComboBox.superclass.onDestroy.call(this);
42737 fireKey : function(e){
42738 if(e.isNavKeyPress() && !this.list.isVisible()){
42739 this.fireEvent("specialkey", this, e);
42744 onResize: function(w, h){
42745 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
42747 if(typeof w != 'number'){
42748 // we do not handle it!?!?
42751 var tw = this.trigger.getWidth();
42752 tw += this.addicon ? this.addicon.getWidth() : 0;
42753 tw += this.editicon ? this.editicon.getWidth() : 0;
42755 this.el.setWidth( this.adjustWidth('input', x));
42757 this.trigger.setStyle('left', x+'px');
42759 if(this.list && this.listWidth === undefined){
42760 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
42761 this.list.setWidth(lw);
42762 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
42770 * Allow or prevent the user from directly editing the field text. If false is passed,
42771 * the user will only be able to select from the items defined in the dropdown list. This method
42772 * is the runtime equivalent of setting the 'editable' config option at config time.
42773 * @param {Boolean} value True to allow the user to directly edit the field text
42775 setEditable : function(value){
42776 if(value == this.editable){
42779 this.editable = value;
42781 this.el.dom.setAttribute('readOnly', true);
42782 this.el.on('mousedown', this.onTriggerClick, this);
42783 this.el.addClass('x-combo-noedit');
42785 this.el.dom.setAttribute('readOnly', false);
42786 this.el.un('mousedown', this.onTriggerClick, this);
42787 this.el.removeClass('x-combo-noedit');
42792 onBeforeLoad : function(){
42793 if(!this.hasFocus){
42796 this.innerList.update(this.loadingText ?
42797 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
42798 this.restrictHeight();
42799 this.selectedIndex = -1;
42803 onLoad : function(){
42804 if(!this.hasFocus){
42807 if(this.store.getCount() > 0){
42809 this.restrictHeight();
42810 if(this.lastQuery == this.allQuery){
42812 this.el.dom.select();
42814 if(!this.selectByValue(this.value, true)){
42815 this.select(0, true);
42819 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
42820 this.taTask.delay(this.typeAheadDelay);
42824 this.onEmptyResults();
42829 onLoadException : function()
42832 Roo.log(this.store.reader.jsonData);
42833 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
42834 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
42840 onTypeAhead : function(){
42841 if(this.store.getCount() > 0){
42842 var r = this.store.getAt(0);
42843 var newValue = r.data[this.displayField];
42844 var len = newValue.length;
42845 var selStart = this.getRawValue().length;
42846 if(selStart != len){
42847 this.setRawValue(newValue);
42848 this.selectText(selStart, newValue.length);
42854 onSelect : function(record, index){
42855 if(this.fireEvent('beforeselect', this, record, index) !== false){
42856 this.setFromData(index > -1 ? record.data : false);
42858 this.fireEvent('select', this, record, index);
42863 * Returns the currently selected field value or empty string if no value is set.
42864 * @return {String} value The selected value
42866 getValue : function(){
42867 if(this.valueField){
42868 return typeof this.value != 'undefined' ? this.value : '';
42870 return Roo.form.ComboBox.superclass.getValue.call(this);
42874 * Clears any text/value currently set in the field
42876 clearValue : function(){
42877 if(this.hiddenField){
42878 this.hiddenField.value = '';
42881 this.setRawValue('');
42882 this.lastSelectionText = '';
42887 * Sets the specified value into the field. If the value finds a match, the corresponding record text
42888 * will be displayed in the field. If the value does not match the data value of an existing item,
42889 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
42890 * Otherwise the field will be blank (although the value will still be set).
42891 * @param {String} value The value to match
42893 setValue : function(v){
42895 if(this.valueField){
42896 var r = this.findRecord(this.valueField, v);
42898 text = r.data[this.displayField];
42899 }else if(this.valueNotFoundText !== undefined){
42900 text = this.valueNotFoundText;
42903 this.lastSelectionText = text;
42904 if(this.hiddenField){
42905 this.hiddenField.value = v;
42907 Roo.form.ComboBox.superclass.setValue.call(this, text);
42911 * @property {Object} the last set data for the element
42916 * Sets the value of the field based on a object which is related to the record format for the store.
42917 * @param {Object} value the value to set as. or false on reset?
42919 setFromData : function(o){
42920 var dv = ''; // display value
42921 var vv = ''; // value value..
42923 if (this.displayField) {
42924 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
42926 // this is an error condition!!!
42927 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
42930 if(this.valueField){
42931 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
42933 if(this.hiddenField){
42934 this.hiddenField.value = vv;
42936 this.lastSelectionText = dv;
42937 Roo.form.ComboBox.superclass.setValue.call(this, dv);
42941 // no hidden field.. - we store the value in 'value', but still display
42942 // display field!!!!
42943 this.lastSelectionText = dv;
42944 Roo.form.ComboBox.superclass.setValue.call(this, dv);
42950 reset : function(){
42951 // overridden so that last data is reset..
42952 this.setValue(this.resetValue);
42953 this.originalValue = this.getValue();
42954 this.clearInvalid();
42955 this.lastData = false;
42957 this.view.clearSelections();
42961 findRecord : function(prop, value){
42963 if(this.store.getCount() > 0){
42964 this.store.each(function(r){
42965 if(r.data[prop] == value){
42975 getName: function()
42977 // returns hidden if it's set..
42978 if (!this.rendered) {return ''};
42979 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
42983 onViewMove : function(e, t){
42984 this.inKeyMode = false;
42988 onViewOver : function(e, t){
42989 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
42992 var item = this.view.findItemFromChild(t);
42994 var index = this.view.indexOf(item);
42995 this.select(index, false);
43000 onViewClick : function(doFocus)
43002 var index = this.view.getSelectedIndexes()[0];
43003 var r = this.store.getAt(index);
43005 this.onSelect(r, index);
43007 if(doFocus !== false && !this.blockFocus){
43013 restrictHeight : function(){
43014 this.innerList.dom.style.height = '';
43015 var inner = this.innerList.dom;
43016 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
43017 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
43018 this.list.beginUpdate();
43019 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
43020 this.list.alignTo(this.el, this.listAlign);
43021 this.list.endUpdate();
43025 onEmptyResults : function(){
43030 * Returns true if the dropdown list is expanded, else false.
43032 isExpanded : function(){
43033 return this.list.isVisible();
43037 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
43038 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
43039 * @param {String} value The data value of the item to select
43040 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
43041 * selected item if it is not currently in view (defaults to true)
43042 * @return {Boolean} True if the value matched an item in the list, else false
43044 selectByValue : function(v, scrollIntoView){
43045 if(v !== undefined && v !== null){
43046 var r = this.findRecord(this.valueField || this.displayField, v);
43048 this.select(this.store.indexOf(r), scrollIntoView);
43056 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
43057 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
43058 * @param {Number} index The zero-based index of the list item to select
43059 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
43060 * selected item if it is not currently in view (defaults to true)
43062 select : function(index, scrollIntoView){
43063 this.selectedIndex = index;
43064 this.view.select(index);
43065 if(scrollIntoView !== false){
43066 var el = this.view.getNode(index);
43068 this.innerList.scrollChildIntoView(el, false);
43074 selectNext : function(){
43075 var ct = this.store.getCount();
43077 if(this.selectedIndex == -1){
43079 }else if(this.selectedIndex < ct-1){
43080 this.select(this.selectedIndex+1);
43086 selectPrev : function(){
43087 var ct = this.store.getCount();
43089 if(this.selectedIndex == -1){
43091 }else if(this.selectedIndex != 0){
43092 this.select(this.selectedIndex-1);
43098 onKeyUp : function(e){
43099 if(this.editable !== false && !e.isSpecialKey()){
43100 this.lastKey = e.getKey();
43101 this.dqTask.delay(this.queryDelay);
43106 validateBlur : function(){
43107 return !this.list || !this.list.isVisible();
43111 initQuery : function(){
43112 this.doQuery(this.getRawValue());
43116 doForce : function(){
43117 if(this.el.dom.value.length > 0){
43118 this.el.dom.value =
43119 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
43125 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
43126 * query allowing the query action to be canceled if needed.
43127 * @param {String} query The SQL query to execute
43128 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
43129 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
43130 * saved in the current store (defaults to false)
43132 doQuery : function(q, forceAll){
43133 if(q === undefined || q === null){
43138 forceAll: forceAll,
43142 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
43146 forceAll = qe.forceAll;
43147 if(forceAll === true || (q.length >= this.minChars)){
43148 if(this.lastQuery != q || this.alwaysQuery){
43149 this.lastQuery = q;
43150 if(this.mode == 'local'){
43151 this.selectedIndex = -1;
43153 this.store.clearFilter();
43155 this.store.filter(this.displayField, q);
43159 this.store.baseParams[this.queryParam] = q;
43161 params: this.getParams(q)
43166 this.selectedIndex = -1;
43173 getParams : function(q){
43175 //p[this.queryParam] = q;
43178 p.limit = this.pageSize;
43184 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
43186 collapse : function(){
43187 if(!this.isExpanded()){
43191 Roo.get(document).un('mousedown', this.collapseIf, this);
43192 Roo.get(document).un('mousewheel', this.collapseIf, this);
43193 if (!this.editable) {
43194 Roo.get(document).un('keydown', this.listKeyPress, this);
43196 this.fireEvent('collapse', this);
43200 collapseIf : function(e){
43201 if(!e.within(this.wrap) && !e.within(this.list)){
43207 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
43209 expand : function(){
43210 if(this.isExpanded() || !this.hasFocus){
43213 this.list.alignTo(this.el, this.listAlign);
43215 Roo.get(document).on('mousedown', this.collapseIf, this);
43216 Roo.get(document).on('mousewheel', this.collapseIf, this);
43217 if (!this.editable) {
43218 Roo.get(document).on('keydown', this.listKeyPress, this);
43221 this.fireEvent('expand', this);
43225 // Implements the default empty TriggerField.onTriggerClick function
43226 onTriggerClick : function(){
43230 if(this.isExpanded()){
43232 if (!this.blockFocus) {
43237 this.hasFocus = true;
43238 if(this.triggerAction == 'all') {
43239 this.doQuery(this.allQuery, true);
43241 this.doQuery(this.getRawValue());
43243 if (!this.blockFocus) {
43248 listKeyPress : function(e)
43250 //Roo.log('listkeypress');
43251 // scroll to first matching element based on key pres..
43252 if (e.isSpecialKey()) {
43255 var k = String.fromCharCode(e.getKey()).toUpperCase();
43258 var csel = this.view.getSelectedNodes();
43259 var cselitem = false;
43261 var ix = this.view.indexOf(csel[0]);
43262 cselitem = this.store.getAt(ix);
43263 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
43269 this.store.each(function(v) {
43271 // start at existing selection.
43272 if (cselitem.id == v.id) {
43278 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
43279 match = this.store.indexOf(v);
43284 if (match === false) {
43285 return true; // no more action?
43288 this.view.select(match);
43289 var sn = Roo.get(this.view.getSelectedNodes()[0]);
43290 sn.scrollIntoView(sn.dom.parentNode, false);
43294 * @cfg {Boolean} grow
43298 * @cfg {Number} growMin
43302 * @cfg {Number} growMax
43310 * Copyright(c) 2010-2012, Roo J Solutions Limited
43317 * @class Roo.form.ComboBoxArray
43318 * @extends Roo.form.TextField
43319 * A facebook style adder... for lists of email / people / countries etc...
43320 * pick multiple items from a combo box, and shows each one.
43322 * Fred [x] Brian [x] [Pick another |v]
43325 * For this to work: it needs various extra information
43326 * - normal combo problay has
43328 * + displayField, valueField
43330 * For our purpose...
43333 * If we change from 'extends' to wrapping...
43340 * Create a new ComboBoxArray.
43341 * @param {Object} config Configuration options
43345 Roo.form.ComboBoxArray = function(config)
43349 * @event beforeremove
43350 * Fires before remove the value from the list
43351 * @param {Roo.form.ComboBoxArray} _self This combo box array
43352 * @param {Roo.form.ComboBoxArray.Item} item removed item
43354 'beforeremove' : true,
43357 * Fires when remove the value from the list
43358 * @param {Roo.form.ComboBoxArray} _self This combo box array
43359 * @param {Roo.form.ComboBoxArray.Item} item removed item
43366 Roo.form.ComboBoxArray.superclass.constructor.call(this, config);
43368 this.items = new Roo.util.MixedCollection(false);
43370 // construct the child combo...
43380 Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
43383 * @cfg {Roo.form.ComboBox} combo [required] The combo box that is wrapped
43388 // behavies liek a hiddne field
43389 inputType: 'hidden',
43391 * @cfg {Number} width The width of the box that displays the selected element
43398 * @cfg {String} name The name of the visable items on this form (eg. titles not ids)
43402 * @cfg {String} hiddenName The hidden name of the field, often contains an comma seperated list of names
43404 hiddenName : false,
43406 * @cfg {String} seperator The value seperator normally ','
43410 // private the array of items that are displayed..
43412 // private - the hidden field el.
43414 // private - the filed el..
43417 //validateValue : function() { return true; }, // all values are ok!
43418 //onAddClick: function() { },
43420 onRender : function(ct, position)
43423 // create the standard hidden element
43424 //Roo.form.ComboBoxArray.superclass.onRender.call(this, ct, position);
43427 // give fake names to child combo;
43428 this.combo.hiddenName = this.hiddenName ? (this.hiddenName+'-subcombo') : this.hiddenName;
43429 this.combo.name = this.name ? (this.name+'-subcombo') : this.name;
43431 this.combo = Roo.factory(this.combo, Roo.form);
43432 this.combo.onRender(ct, position);
43433 if (typeof(this.combo.width) != 'undefined') {
43434 this.combo.onResize(this.combo.width,0);
43437 this.combo.initEvents();
43439 // assigned so form know we need to do this..
43440 this.store = this.combo.store;
43441 this.valueField = this.combo.valueField;
43442 this.displayField = this.combo.displayField ;
43445 this.combo.wrap.addClass('x-cbarray-grp');
43447 var cbwrap = this.combo.wrap.createChild(
43448 {tag: 'div', cls: 'x-cbarray-cb'},
43453 this.hiddenEl = this.combo.wrap.createChild({
43454 tag: 'input', type:'hidden' , name: this.hiddenName, value : ''
43456 this.el = this.combo.wrap.createChild({
43457 tag: 'input', type:'hidden' , name: this.name, value : ''
43459 // this.el.dom.removeAttribute("name");
43462 this.outerWrap = this.combo.wrap;
43463 this.wrap = cbwrap;
43465 this.outerWrap.setWidth(this.width);
43466 this.outerWrap.dom.removeChild(this.el.dom);
43468 this.wrap.dom.appendChild(this.el.dom);
43469 this.outerWrap.dom.removeChild(this.combo.trigger.dom);
43470 this.combo.wrap.dom.appendChild(this.combo.trigger.dom);
43472 this.combo.trigger.setStyle('position','relative');
43473 this.combo.trigger.setStyle('left', '0px');
43474 this.combo.trigger.setStyle('top', '2px');
43476 this.combo.el.setStyle('vertical-align', 'text-bottom');
43478 //this.trigger.setStyle('vertical-align', 'top');
43480 // this should use the code from combo really... on('add' ....)
43484 this.adder = this.outerWrap.createChild(
43485 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-adder', style: 'margin-left:2px'});
43487 this.adder.on('click', function(e) {
43488 _t.fireEvent('adderclick', this, e);
43492 //this.adder.on('click', this.onAddClick, _t);
43495 this.combo.on('select', function(cb, rec, ix) {
43496 this.addItem(rec.data);
43499 cb.el.dom.value = '';
43500 //cb.lastData = rec.data;
43509 getName: function()
43511 // returns hidden if it's set..
43512 if (!this.rendered) {return ''};
43513 return this.hiddenName ? this.hiddenName : this.name;
43518 onResize: function(w, h){
43521 // not sure if this is needed..
43522 //this.combo.onResize(w,h);
43524 if(typeof w != 'number'){
43525 // we do not handle it!?!?
43528 var tw = this.combo.trigger.getWidth();
43529 tw += this.addicon ? this.addicon.getWidth() : 0;
43530 tw += this.editicon ? this.editicon.getWidth() : 0;
43532 this.combo.el.setWidth( this.combo.adjustWidth('input', x));
43534 this.combo.trigger.setStyle('left', '0px');
43536 if(this.list && this.listWidth === undefined){
43537 var lw = Math.max(x + this.combo.trigger.getWidth(), this.combo.minListWidth);
43538 this.list.setWidth(lw);
43539 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
43546 addItem: function(rec)
43548 var valueField = this.combo.valueField;
43549 var displayField = this.combo.displayField;
43551 if (this.items.indexOfKey(rec[valueField]) > -1) {
43552 //console.log("GOT " + rec.data.id);
43556 var x = new Roo.form.ComboBoxArray.Item({
43557 //id : rec[this.idField],
43559 displayField : displayField ,
43560 tipField : displayField ,
43564 this.items.add(rec[valueField],x);
43565 // add it before the element..
43566 this.updateHiddenEl();
43567 x.render(this.outerWrap, this.wrap.dom);
43568 // add the image handler..
43571 updateHiddenEl : function()
43574 if (!this.hiddenEl) {
43578 var idField = this.combo.valueField;
43580 this.items.each(function(f) {
43581 ar.push(f.data[idField]);
43583 this.hiddenEl.dom.value = ar.join(this.seperator);
43589 this.items.clear();
43591 Roo.each(this.outerWrap.select('.x-cbarray-item', true).elements, function(el){
43595 this.el.dom.value = '';
43596 if (this.hiddenEl) {
43597 this.hiddenEl.dom.value = '';
43601 getValue: function()
43603 return this.hiddenEl ? this.hiddenEl.dom.value : '';
43605 setValue: function(v) // not a valid action - must use addItems..
43610 if (this.store.isLocal && (typeof(v) == 'string')) {
43611 // then we can use the store to find the values..
43612 // comma seperated at present.. this needs to allow JSON based encoding..
43613 this.hiddenEl.value = v;
43615 Roo.each(v.split(this.seperator), function(k) {
43616 Roo.log("CHECK " + this.valueField + ',' + k);
43617 var li = this.store.query(this.valueField, k);
43622 add[this.valueField] = k;
43623 add[this.displayField] = li.item(0).data[this.displayField];
43629 if (typeof(v) == 'object' ) {
43630 // then let's assume it's an array of objects..
43631 Roo.each(v, function(l) {
43633 if (typeof(l) == 'string') {
43635 add[this.valueField] = l;
43636 add[this.displayField] = l
43645 setFromData: function(v)
43647 // this recieves an object, if setValues is called.
43649 this.el.dom.value = v[this.displayField];
43650 this.hiddenEl.dom.value = v[this.valueField];
43651 if (typeof(v[this.valueField]) != 'string' || !v[this.valueField].length) {
43654 var kv = v[this.valueField];
43655 var dv = v[this.displayField];
43656 kv = typeof(kv) != 'string' ? '' : kv;
43657 dv = typeof(dv) != 'string' ? '' : dv;
43660 var keys = kv.split(this.seperator);
43661 var display = dv.split(this.seperator);
43662 for (var i = 0 ; i < keys.length; i++) {
43664 add[this.valueField] = keys[i];
43665 add[this.displayField] = display[i];
43673 * Validates the combox array value
43674 * @return {Boolean} True if the value is valid, else false
43676 validate : function(){
43677 if(this.disabled || this.validateValue(this.processValue(this.getValue()))){
43678 this.clearInvalid();
43684 validateValue : function(value){
43685 return Roo.form.ComboBoxArray.superclass.validateValue.call(this, this.getValue());
43693 isDirty : function() {
43694 if(this.disabled) {
43699 var d = Roo.decode(String(this.originalValue));
43701 return String(this.getValue()) !== String(this.originalValue);
43704 var originalValue = [];
43706 for (var i = 0; i < d.length; i++){
43707 originalValue.push(d[i][this.valueField]);
43710 return String(this.getValue()) !== String(originalValue.join(this.seperator));
43719 * @class Roo.form.ComboBoxArray.Item
43720 * @extends Roo.BoxComponent
43721 * A selected item in the list
43722 * Fred [x] Brian [x] [Pick another |v]
43725 * Create a new item.
43726 * @param {Object} config Configuration options
43729 Roo.form.ComboBoxArray.Item = function(config) {
43730 config.id = Roo.id();
43731 Roo.form.ComboBoxArray.Item.superclass.constructor.call(this, config);
43734 Roo.extend(Roo.form.ComboBoxArray.Item, Roo.BoxComponent, {
43737 displayField : false,
43741 defaultAutoCreate : {
43743 cls: 'x-cbarray-item',
43750 src : Roo.BLANK_IMAGE_URL ,
43758 onRender : function(ct, position)
43760 Roo.form.Field.superclass.onRender.call(this, ct, position);
43763 var cfg = this.getAutoCreate();
43764 this.el = ct.createChild(cfg, position);
43767 this.el.child('img').dom.setAttribute('src', Roo.BLANK_IMAGE_URL);
43769 this.el.child('div').dom.innerHTML = this.cb.renderer ?
43770 this.cb.renderer(this.data) :
43771 String.format('{0}',this.data[this.displayField]);
43774 this.el.child('div').dom.setAttribute('qtip',
43775 String.format('{0}',this.data[this.tipField])
43778 this.el.child('img').on('click', this.remove, this);
43782 remove : function()
43784 if(this.cb.disabled){
43788 if(false !== this.cb.fireEvent('beforeremove', this.cb, this)){
43789 this.cb.items.remove(this);
43790 this.el.child('img').un('click', this.remove, this);
43792 this.cb.updateHiddenEl();
43794 this.cb.fireEvent('remove', this.cb, this);
43799 * RooJS Library 1.1.1
43800 * Copyright(c) 2008-2011 Alan Knowles
43807 * @class Roo.form.ComboNested
43808 * @extends Roo.form.ComboBox
43809 * A combobox for that allows selection of nested items in a list,
43824 * Create a new ComboNested
43825 * @param {Object} config Configuration options
43827 Roo.form.ComboNested = function(config){
43828 Roo.form.ComboCheck.superclass.constructor.call(this, config);
43829 // should verify some data...
43831 // hiddenName = required..
43832 // displayField = required
43833 // valudField == required
43834 var req= [ 'hiddenName', 'displayField', 'valueField' ];
43836 Roo.each(req, function(e) {
43837 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
43838 throw "Roo.form.ComboNested : missing value for: " + e;
43845 Roo.extend(Roo.form.ComboNested, Roo.form.ComboBox, {
43848 * @config {Number} max Number of columns to show
43853 list : null, // the outermost div..
43854 innerLists : null, // the
43858 loadingChildren : false,
43860 onRender : function(ct, position)
43862 Roo.form.ComboBox.superclass.onRender.call(this, ct, position); // skip parent call - got to above..
43864 if(this.hiddenName){
43865 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
43867 this.hiddenField.value =
43868 this.hiddenValue !== undefined ? this.hiddenValue :
43869 this.value !== undefined ? this.value : '';
43871 // prevent input submission
43872 this.el.dom.removeAttribute('name');
43878 this.el.dom.setAttribute('autocomplete', 'off');
43881 var cls = 'x-combo-list';
43883 this.list = new Roo.Layer({
43884 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
43887 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
43888 this.list.setWidth(lw);
43889 this.list.swallowEvent('mousewheel');
43890 this.assetHeight = 0;
43893 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
43894 this.assetHeight += this.header.getHeight();
43896 this.innerLists = [];
43899 for (var i =0 ; i < this.maxColumns; i++) {
43900 this.onRenderList( cls, i);
43903 // always needs footer, as we are going to have an 'OK' button.
43904 this.footer = this.list.createChild({cls:cls+'-ft'});
43905 this.pageTb = new Roo.Toolbar(this.footer);
43910 handler: function()
43916 if ( this.allowBlank && !this.disableClear) {
43918 this.pageTb.add(new Roo.Toolbar.Fill(), {
43919 cls: 'x-btn-icon x-btn-clear',
43921 handler: function()
43924 _this.clearValue();
43925 _this.onSelect(false, -1);
43930 this.assetHeight += this.footer.getHeight();
43934 onRenderList : function ( cls, i)
43937 var lw = Math.floor(
43938 ((this.listWidth * this.maxColumns || Math.max(this.wrap.getWidth(), this.minListWidth)) - this.list.getFrameWidth('lr')) / this.maxColumns
43941 this.list.setWidth(lw); // default to '1'
43943 var il = this.innerLists[i] = this.list.createChild({cls:cls+'-inner'});
43944 //il.on('mouseover', this.onViewOver, this, { list: i });
43945 //il.on('mousemove', this.onViewMove, this, { list: i });
43947 il.setStyle({ 'overflow-x' : 'hidden'});
43950 this.tpl = new Roo.Template({
43951 html : '<div class="'+cls+'-item '+cls+'-item-{cn:this.isEmpty}">{' + this.displayField + '}</div>',
43952 isEmpty: function (value, allValues) {
43954 var dl = typeof(value.data) != 'undefined' ? value.data.length : value.length; ///json is a nested response..
43955 return dl ? 'has-children' : 'no-children'
43960 var store = this.store;
43962 store = new Roo.data.SimpleStore({
43963 //fields : this.store.reader.meta.fields,
43964 reader : this.store.reader,
43968 this.stores[i] = store;
43970 var view = this.views[i] = new Roo.View(
43976 selectedClass: this.selectedClass
43979 view.getEl().setWidth(lw);
43980 view.getEl().setStyle({
43981 position: i < 1 ? 'relative' : 'absolute',
43983 left: (i * lw ) + 'px',
43984 display : i > 0 ? 'none' : 'block'
43986 view.on('selectionchange', this.onSelectChange.createDelegate(this, {list : i }, true));
43987 view.on('dblclick', this.onDoubleClick.createDelegate(this, {list : i }, true));
43988 //view.on('click', this.onViewClick, this, { list : i });
43990 store.on('beforeload', this.onBeforeLoad, this);
43991 store.on('load', this.onLoad, this, { list : i});
43992 store.on('loadexception', this.onLoadException, this);
43994 // hide the other vies..
44000 restrictHeight : function()
44003 Roo.each(this.innerLists, function(il,i) {
44004 var el = this.views[i].getEl();
44005 el.dom.style.height = '';
44006 var inner = el.dom;
44007 var h = Math.max(il.clientHeight, il.offsetHeight, il.scrollHeight);
44008 // only adjust heights on other ones..
44009 mh = Math.max(h, mh);
44012 el.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
44013 il.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
44020 this.list.beginUpdate();
44021 this.list.setHeight(mh+this.list.getFrameWidth('tb')+this.assetHeight);
44022 this.list.alignTo(this.el, this.listAlign);
44023 this.list.endUpdate();
44028 // -- store handlers..
44030 onBeforeLoad : function()
44032 if(!this.hasFocus){
44035 this.innerLists[0].update(this.loadingText ?
44036 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
44037 this.restrictHeight();
44038 this.selectedIndex = -1;
44041 onLoad : function(a,b,c,d)
44043 if (!this.loadingChildren) {
44044 // then we are loading the top level. - hide the children
44045 for (var i = 1;i < this.views.length; i++) {
44046 this.views[i].getEl().setStyle({ display : 'none' });
44048 var lw = Math.floor(
44049 ((this.listWidth * this.maxColumns || Math.max(this.wrap.getWidth(), this.minListWidth)) - this.list.getFrameWidth('lr')) / this.maxColumns
44052 this.list.setWidth(lw); // default to '1'
44056 if(!this.hasFocus){
44060 if(this.store.getCount() > 0) {
44062 this.restrictHeight();
44064 this.onEmptyResults();
44067 if (!this.loadingChildren) {
44068 this.selectActive();
44071 this.stores[1].loadData([]);
44072 this.stores[2].loadData([]);
44081 onLoadException : function()
44084 Roo.log(this.store.reader.jsonData);
44085 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
44086 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
44091 // no cleaning of leading spaces on blur here.
44092 cleanLeadingSpace : function(e) { },
44095 onSelectChange : function (view, sels, opts )
44097 var ix = view.getSelectedIndexes();
44099 if (opts.list > this.maxColumns - 2) {
44100 if (view.store.getCount()< 1) {
44101 this.views[opts.list ].getEl().setStyle({ display : 'none' });
44105 // used to clear ?? but if we are loading unselected
44106 this.setFromData(view.store.getAt(ix[0]).data);
44115 // this get's fired when trigger opens..
44116 // this.setFromData({});
44117 var str = this.stores[opts.list+1];
44118 str.data.clear(); // removeall wihtout the fire events..
44122 var rec = view.store.getAt(ix[0]);
44124 this.setFromData(rec.data);
44125 this.fireEvent('select', this, rec, ix[0]);
44127 var lw = Math.floor(
44129 (this.listWidth * this.maxColumns || Math.max(this.wrap.getWidth(), this.minListWidth)) - this.list.getFrameWidth('lr')
44130 ) / this.maxColumns
44132 this.loadingChildren = true;
44133 this.stores[opts.list+1].loadDataFromChildren( rec );
44134 this.loadingChildren = false;
44135 var dl = this.stores[opts.list+1]. getTotalCount();
44137 this.views[opts.list+1].getEl().setHeight( this.innerLists[0].getHeight());
44139 this.views[opts.list+1].getEl().setStyle({ display : dl ? 'block' : 'none' });
44140 for (var i = opts.list+2; i < this.views.length;i++) {
44141 this.views[i].getEl().setStyle({ display : 'none' });
44144 this.innerLists[opts.list+1].setHeight( this.innerLists[0].getHeight());
44145 this.list.setWidth(lw * (opts.list + (dl ? 2 : 1)));
44147 if (this.isLoading) {
44148 // this.selectActive(opts.list);
44156 onDoubleClick : function()
44158 this.collapse(); //??
44166 recordToStack : function(store, prop, value, stack)
44168 var cstore = new Roo.data.SimpleStore({
44169 //fields : this.store.reader.meta.fields, // we need array reader.. for
44170 reader : this.store.reader,
44174 var record = false;
44176 if(store.getCount() < 1){
44179 store.each(function(r){
44180 if(r.data[prop] == value){
44185 if (r.data.cn && r.data.cn.length) {
44186 cstore.loadDataFromChildren( r);
44187 var cret = _this.recordToStack(cstore, prop, value, stack);
44188 if (cret !== false) {
44197 if (record == false) {
44200 stack.unshift(srec);
44205 * find the stack of stores that match our value.
44210 selectActive : function ()
44212 // if store is not loaded, then we will need to wait for that to happen first.
44214 this.recordToStack(this.store, this.valueField, this.getValue(), stack);
44215 for (var i = 0; i < stack.length; i++ ) {
44216 this.views[i].select(stack[i].store.indexOf(stack[i]), false, false );
44228 * Ext JS Library 1.1.1
44229 * Copyright(c) 2006-2007, Ext JS, LLC.
44231 * Originally Released Under LGPL - original licence link has changed is not relivant.
44234 * <script type="text/javascript">
44237 * @class Roo.form.Checkbox
44238 * @extends Roo.form.Field
44239 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
44241 * Creates a new Checkbox
44242 * @param {Object} config Configuration options
44244 Roo.form.Checkbox = function(config){
44245 Roo.form.Checkbox.superclass.constructor.call(this, config);
44249 * Fires when the checkbox is checked or unchecked.
44250 * @param {Roo.form.Checkbox} this This checkbox
44251 * @param {Boolean} checked The new checked value
44257 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
44259 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
44261 focusClass : undefined,
44263 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
44265 fieldClass: "x-form-field",
44267 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
44271 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
44272 * {tag: "input", type: "checkbox", autocomplete: "off"})
44274 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
44276 * @cfg {String} boxLabel The text that appears beside the checkbox
44280 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
44284 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
44286 valueOff: '0', // value when not checked..
44288 actionMode : 'viewEl',
44291 itemCls : 'x-menu-check-item x-form-item',
44292 groupClass : 'x-menu-group-item',
44293 inputType : 'hidden',
44296 inSetChecked: false, // check that we are not calling self...
44298 inputElement: false, // real input element?
44299 basedOn: false, // ????
44301 isFormField: true, // not sure where this is needed!!!!
44303 onResize : function(){
44304 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
44305 if(!this.boxLabel){
44306 this.el.alignTo(this.wrap, 'c-c');
44310 initEvents : function(){
44311 Roo.form.Checkbox.superclass.initEvents.call(this);
44312 this.el.on("click", this.onClick, this);
44313 this.el.on("change", this.onClick, this);
44317 getResizeEl : function(){
44321 getPositionEl : function(){
44326 onRender : function(ct, position){
44327 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
44329 if(this.inputValue !== undefined){
44330 this.el.dom.value = this.inputValue;
44333 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
44334 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
44335 var viewEl = this.wrap.createChild({
44336 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
44337 this.viewEl = viewEl;
44338 this.wrap.on('click', this.onClick, this);
44340 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
44341 this.el.on('propertychange', this.setFromHidden, this); //ie
44346 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
44347 // viewEl.on('click', this.onClick, this);
44349 //if(this.checked){
44350 this.setChecked(this.checked);
44352 //this.checked = this.el.dom;
44358 initValue : Roo.emptyFn,
44361 * Returns the checked state of the checkbox.
44362 * @return {Boolean} True if checked, else false
44364 getValue : function(){
44366 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
44368 return this.valueOff;
44373 onClick : function(){
44374 if (this.disabled) {
44377 this.setChecked(!this.checked);
44379 //if(this.el.dom.checked != this.checked){
44380 // this.setValue(this.el.dom.checked);
44385 * Sets the checked state of the checkbox.
44386 * On is always based on a string comparison between inputValue and the param.
44387 * @param {Boolean/String} value - the value to set
44388 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
44390 setValue : function(v,suppressEvent){
44393 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
44394 //if(this.el && this.el.dom){
44395 // this.el.dom.checked = this.checked;
44396 // this.el.dom.defaultChecked = this.checked;
44398 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
44399 //this.fireEvent("check", this, this.checked);
44402 setChecked : function(state,suppressEvent)
44404 if (this.inSetChecked) {
44405 this.checked = state;
44411 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
44413 this.checked = state;
44414 if(suppressEvent !== true){
44415 this.fireEvent('check', this, state);
44417 this.inSetChecked = true;
44418 this.el.dom.value = state ? this.inputValue : this.valueOff;
44419 this.inSetChecked = false;
44422 // handle setting of hidden value by some other method!!?!?
44423 setFromHidden: function()
44428 //console.log("SET FROM HIDDEN");
44429 //alert('setFrom hidden');
44430 this.setValue(this.el.dom.value);
44433 onDestroy : function()
44436 Roo.get(this.viewEl).remove();
44439 Roo.form.Checkbox.superclass.onDestroy.call(this);
44442 setBoxLabel : function(str)
44444 this.wrap.select('.x-form-cb-label', true).first().dom.innerHTML = str;
44449 * Ext JS Library 1.1.1
44450 * Copyright(c) 2006-2007, Ext JS, LLC.
44452 * Originally Released Under LGPL - original licence link has changed is not relivant.
44455 * <script type="text/javascript">
44459 * @class Roo.form.Radio
44460 * @extends Roo.form.Checkbox
44461 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
44462 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
44464 * Creates a new Radio
44465 * @param {Object} config Configuration options
44467 Roo.form.Radio = function(){
44468 Roo.form.Radio.superclass.constructor.apply(this, arguments);
44470 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
44471 inputType: 'radio',
44474 * If this radio is part of a group, it will return the selected value
44477 getGroupValue : function(){
44478 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
44482 onRender : function(ct, position){
44483 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
44485 if(this.inputValue !== undefined){
44486 this.el.dom.value = this.inputValue;
44489 this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
44490 //this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
44491 //var viewEl = this.wrap.createChild({
44492 // tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
44493 //this.viewEl = viewEl;
44494 //this.wrap.on('click', this.onClick, this);
44496 //this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
44497 //this.el.on('propertychange', this.setFromHidden, this); //ie
44502 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
44503 // viewEl.on('click', this.onClick, this);
44506 this.el.dom.checked = 'checked' ;
44512 });Roo.htmleditor = {};
44514 * @class Roo.htmleditor.Filter
44515 * Base Class for filtering htmleditor stuff. - do not use this directly - extend it.
44516 * @cfg {DomElement} node The node to iterate and filter
44517 * @cfg {boolean|String|Array} tag Tags to replace
44519 * Create a new Filter.
44520 * @param {Object} config Configuration options
44525 Roo.htmleditor.Filter = function(cfg) {
44526 Roo.apply(this.cfg);
44527 // this does not actually call walk as it's really just a abstract class
44531 Roo.htmleditor.Filter.prototype = {
44537 // overrride to do replace comments.
44538 replaceComment : false,
44540 // overrride to do replace or do stuff with tags..
44541 replaceTag : false,
44543 walk : function(dom)
44545 Roo.each( Array.from(dom.childNodes), function( e ) {
44548 case e.nodeType == 8 && typeof(this.replaceComment) != 'undefined': // comment
44549 this.replaceComment(e);
44552 case e.nodeType != 1: //not a node.
44555 case this.tag === true: // everything
44556 case typeof(this.tag) == 'object' && this.tag.indexOf(e.tagName) > -1: // array and it matches.
44557 case typeof(this.tag) == 'string' && this.tag == e.tagName: // array and it matches.
44558 if (this.replaceTag && false === this.replaceTag(e)) {
44561 if (e.hasChildNodes()) {
44566 default: // tags .. that do not match.
44567 if (e.hasChildNodes()) {
44578 * @class Roo.htmleditor.FilterAttributes
44579 * clean attributes and styles including http:// etc.. in attribute
44581 * Run a new Attribute Filter
44582 * @param {Object} config Configuration options
44584 Roo.htmleditor.FilterAttributes = function(cfg)
44586 Roo.apply(this, cfg);
44587 this.attrib_black = this.attrib_black || [];
44588 this.attrib_clean = this.attrib_clean || [];
44589 this.style_white = this.style_white || [];
44590 this.style_black = this.style_black || [];
44591 this.walk(cfg.node);
44594 Roo.extend(Roo.htmleditor.FilterAttributes, Roo.htmleditor.Filter,
44596 tag: true, // all tags
44598 attrib_black : false, // array
44599 attrib_clean : false,
44600 style_white : false,
44601 style_black : false,
44604 replaceTag : function(node)
44606 if (!node.attributes || !node.attributes.length) {
44610 for (var i = node.attributes.length-1; i > -1 ; i--) {
44611 var a = node.attributes[i];
44614 if (a.name.toLowerCase().substr(0,2)=='on') {
44615 node.removeAttribute(a.name);
44620 if (this.attrib_black.indexOf(a.name.toLowerCase()) > -1) {
44621 node.removeAttribute(a.name);
44624 if (this.attrib_clean.indexOf(a.name.toLowerCase()) > -1) {
44625 this.cleanAttr(node,a.name,a.value); // fixme..
44628 if (a.name == 'style') {
44629 this.cleanStyle(node,a.name,a.value);
44632 /// clean up MS crap..
44633 // tecnically this should be a list of valid class'es..
44636 if (a.name == 'class') {
44637 if (a.value.match(/^Mso/)) {
44638 node.removeAttribute('class');
44641 if (a.value.match(/^body$/)) {
44642 node.removeAttribute('class');
44652 return true; // clean children
44655 cleanAttr: function(node, n,v)
44658 if (v.match(/^\./) || v.match(/^\//)) {
44661 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/) || v.match(/^ftp:/)) {
44664 if (v.match(/^#/)) {
44667 if (v.match(/^\{/)) { // allow template editing.
44670 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
44671 node.removeAttribute(n);
44674 cleanStyle : function(node, n,v)
44676 if (v.match(/expression/)) { //XSS?? should we even bother..
44677 node.removeAttribute(n);
44681 var parts = v.split(/;/);
44684 Roo.each(parts, function(p) {
44685 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
44689 var l = p.split(':').shift().replace(/\s+/g,'');
44690 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
44692 if ( this.style_black.length && (this.style_black.indexOf(l) > -1 || this.style_black.indexOf(l.toLowerCase()) > -1)) {
44696 // only allow 'c whitelisted system attributes'
44697 if ( this.style_white.length && style_white.indexOf(l) < 0 && style_white.indexOf(l.toLowerCase()) < 0 ) {
44705 if (clean.length) {
44706 node.setAttribute(n, clean.join(';'));
44708 node.removeAttribute(n);
44717 * @class Roo.htmleditor.FilterBlack
44718 * remove blacklisted elements.
44720 * Run a new Blacklisted Filter
44721 * @param {Object} config Configuration options
44724 Roo.htmleditor.FilterBlack = function(cfg)
44726 Roo.apply(this, cfg);
44727 this.walk(cfg.node);
44730 Roo.extend(Roo.htmleditor.FilterBlack, Roo.htmleditor.Filter,
44732 tag : true, // all elements.
44734 replace : function(n)
44736 n.parentNode.removeChild(n);
44740 * @class Roo.htmleditor.FilterComment
44743 * Run a new Comments Filter
44744 * @param {Object} config Configuration options
44746 Roo.htmleditor.FilterComment = function(cfg)
44748 this.walk(cfg.node);
44751 Roo.extend(Roo.htmleditor.FilterComment, Roo.htmleditor.Filter,
44754 replaceComment : function(n)
44756 n.parentNode.removeChild(n);
44759 * @class Roo.htmleditor.FilterKeepChildren
44760 * remove tags but keep children
44762 * Run a new Keep Children Filter
44763 * @param {Object} config Configuration options
44766 Roo.htmleditor.FilterKeepChildren = function(cfg)
44768 Roo.apply(this, cfg);
44769 if (this.tag === false) {
44770 return; // dont walk.. (you can use this to use this just to do a child removal on a single tag )
44772 this.walk(cfg.node);
44775 Roo.extend(Roo.htmleditor.FilterKeepChildren, Roo.htmleditor.FilterBlack,
44779 replaceTag : function(node)
44781 // walk children...
44782 var ar = Array.from(node.childNodes);
44783 for (var i = 0; i < ar.length; i++) {
44784 node.removeChild(ar[i]);
44785 // what if we need to walk these???
44786 node.parentNode.insertBefore(ar[i], node);
44787 if (this.tag !== false) {
44791 node.parentNode.removeChild(node);
44792 return false; // don't walk children
44797 * @class Roo.htmleditor.FilterParagraph
44798 * paragraphs cause a nightmare for shared content - this filter is designed to be called ? at various points when editing
44799 * like on 'push' to remove the <p> tags and replace them with line breaks.
44801 * Run a new Paragraph Filter
44802 * @param {Object} config Configuration options
44805 Roo.htmleditor.FilterParagraph = function(cfg)
44807 // no need to apply config.
44808 this.walk(cfg.node);
44811 Roo.extend(Roo.htmleditor.FilterParagraph, Roo.htmleditor.Filter,
44818 replaceTag : function(node)
44821 if (node.childNodes.length == 1 &&
44822 node.childNodes[0].nodeType == 3 &&
44823 node.childNodes[0].textContent.trim().length < 1
44825 // remove and replace with '<BR>';
44826 node.parentNode.replaceChild(node.ownerDocument.createElement('BR'),node);
44827 return false; // no need to walk..
44829 var ar = Array.from(node.childNodes);
44830 for (var i = 0; i < ar.length; i++) {
44831 node.removeChild(ar[i]);
44832 // what if we need to walk these???
44833 node.parentNode.insertBefore(ar[i], node);
44835 // now what about this?
44839 node.parentNode.insertBefore(node.ownerDocument.createElement('BR'), node);
44840 node.parentNode.removeChild(node);
44847 * @class Roo.htmleditor.FilterSpan
44848 * filter span's with no attributes out..
44850 * Run a new Span Filter
44851 * @param {Object} config Configuration options
44854 Roo.htmleditor.FilterSpan = function(cfg)
44856 // no need to apply config.
44857 this.walk(cfg.node);
44860 Roo.extend(Roo.htmleditor.FilterSpan, Roo.htmleditor.FilterKeepChildren,
44866 replaceTag : function(node)
44868 if (node.attributes && node.attributes.length > 0) {
44869 return true; // walk if there are any.
44871 Roo.htmleditor.FilterKeepChildren.prototype.replaceTag.call(this, node);
44877 * @class Roo.htmleditor.FilterTableWidth
44878 try and remove table width data - as that frequently messes up other stuff.
44880 * was cleanTableWidths.
44882 * Quite often pasting from word etc.. results in tables with column and widths.
44883 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
44886 * Run a new Table Filter
44887 * @param {Object} config Configuration options
44890 Roo.htmleditor.FilterTableWidth = function(cfg)
44892 // no need to apply config.
44893 this.tag = ['TABLE', 'TD', 'TR', 'TH', 'THEAD', 'TBODY' ];
44894 this.walk(cfg.node);
44897 Roo.extend(Roo.htmleditor.FilterTableWidth, Roo.htmleditor.Filter,
44902 replaceTag: function(node) {
44906 if (node.hasAttribute('width')) {
44907 node.removeAttribute('width');
44911 if (node.hasAttribute("style")) {
44914 var styles = node.getAttribute("style").split(";");
44916 Roo.each(styles, function(s) {
44917 if (!s.match(/:/)) {
44920 var kv = s.split(":");
44921 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
44924 // what ever is left... we allow.
44927 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
44928 if (!nstyle.length) {
44929 node.removeAttribute('style');
44933 return true; // continue doing children..
44936 * @class Roo.htmleditor.FilterWord
44937 * try and clean up all the mess that Word generates.
44939 * This is the 'nice version' - see 'Heavy' that white lists a very short list of elements, and multi-filters
44942 * Run a new Span Filter
44943 * @param {Object} config Configuration options
44946 Roo.htmleditor.FilterWord = function(cfg)
44948 // no need to apply config.
44949 this.walk(cfg.node);
44952 Roo.extend(Roo.htmleditor.FilterWord, Roo.htmleditor.Filter,
44958 * Clean up MS wordisms...
44960 replaceTag : function(node)
44963 // no idea what this does - span with text, replaceds with just text.
44965 node.nodeName == 'SPAN' &&
44966 !node.hasAttributes() &&
44967 node.childNodes.length == 1 &&
44968 node.firstChild.nodeName == "#text"
44970 var textNode = node.firstChild;
44971 node.removeChild(textNode);
44972 if (node.getAttribute('lang') != 'zh-CN') { // do not space pad on chinese characters..
44973 node.parentNode.insertBefore(node.ownerDocument.createTextNode(" "), node);
44975 node.parentNode.insertBefore(textNode, node);
44976 if (node.getAttribute('lang') != 'zh-CN') { // do not space pad on chinese characters..
44977 node.parentNode.insertBefore(node.ownerDocument.createTextNode(" ") , node);
44980 node.parentNode.removeChild(node);
44981 return false; // dont do chidren - we have remove our node - so no need to do chdhilren?
44986 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
44987 node.parentNode.removeChild(node);
44988 return false; // dont do chidlren
44990 //Roo.log(node.tagName);
44991 // remove - but keep children..
44992 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|v:|font)/)) {
44993 //Roo.log('-- removed');
44994 while (node.childNodes.length) {
44995 var cn = node.childNodes[0];
44996 node.removeChild(cn);
44997 node.parentNode.insertBefore(cn, node);
44998 // move node to parent - and clean it..
44999 this.replaceTag(cn);
45001 node.parentNode.removeChild(node);
45002 /// no need to iterate chidlren = it's got none..
45003 //this.iterateChildren(node, this.cleanWord);
45004 return false; // no need to iterate children.
45007 if (node.className.length) {
45009 var cn = node.className.split(/\W+/);
45011 Roo.each(cn, function(cls) {
45012 if (cls.match(/Mso[a-zA-Z]+/)) {
45017 node.className = cna.length ? cna.join(' ') : '';
45019 node.removeAttribute("class");
45023 if (node.hasAttribute("lang")) {
45024 node.removeAttribute("lang");
45027 if (node.hasAttribute("style")) {
45029 var styles = node.getAttribute("style").split(";");
45031 Roo.each(styles, function(s) {
45032 if (!s.match(/:/)) {
45035 var kv = s.split(":");
45036 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
45039 // what ever is left... we allow.
45042 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
45043 if (!nstyle.length) {
45044 node.removeAttribute('style');
45047 return true; // do children
45054 * @class Roo.htmleditor.Tidy
45056 * @cfg {Roo.HtmlEditorCore} core the editor.
45058 * Create a new Filter.
45059 * @param {Object} config Configuration options
45063 Roo.htmleditor.Tidy = function(cfg) {
45064 Roo.apply(this, cfg);
45066 this.core.doc.body.innerHTML = this.tidy(this.core.doc.body, '');
45070 Roo.htmleditor.Tidy.toString = function(node)
45072 return Roo.htmleditor.Tidy.prototype.tidy(node, '');
45075 Roo.htmleditor.Tidy.prototype = {
45078 wrap : function(s) {
45079 return s.replace(/\n/g, " ").replace(/(?![^\n]{1,80}$)([^\n]{1,80})\s/g, '$1\n');
45083 tidy : function(node, indent) {
45085 if (node.nodeType == 3) {
45089 return indent === false ? node.nodeValue : this.wrap(node.nodeValue.trim()).split("\n").join("\n" + indent);
45094 if (node.nodeType != 1) {
45100 if (node.tagName == 'BODY') {
45102 return this.cn(node, '');
45105 // Prints the node tagName, such as <A>, <IMG>, etc
45106 var ret = "<" + node.tagName + this.attr(node) ;
45108 // elements with no children..
45109 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(node.tagName) > -1) {
45115 var cindent = indent === false ? '' : (indent + ' ');
45116 // tags where we will not pad the children.. (inline text tags etc..)
45117 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN', 'B', 'I', 'S'].indexOf(node.tagName) > -1) { // or code?
45123 var cn = this.cn(node, cindent );
45125 return ret + cn + '</' + node.tagName + '>';
45128 cn: function(node, indent)
45132 var ar = Array.from(node.childNodes);
45133 for (var i = 0 ; i < ar.length ; i++) {
45137 if (indent !== false // indent==false preservies everything
45139 && ar[i].nodeType == 3
45140 && ar[i].nodeValue.length > 0
45141 && ar[i].nodeValue.match(/^\s+/)
45143 if (ret.length && ret[ret.length-1] == "\n" + indent) {
45144 ret.pop(); // remove line break from last?
45147 ret.push(" "); // add a space if i'm a text item with a space at the front, as tidy will strip spaces.
45149 if (indent !== false
45150 && ar[i].nodeType == 1 // element - and indent is not set...
45152 ret.push("\n" + indent);
45155 ret.push(this.tidy(ar[i], indent));
45156 // text + trailing indent
45157 if (indent !== false
45158 && ar[i].nodeType == 3
45159 && ar[i].nodeValue.length > 0
45160 && ar[i].nodeValue.match(/\s+$/)
45162 ret.push("\n" + indent);
45169 // what if all text?
45172 return ret.join('');
45177 attr : function(node)
45180 for(i = 0; i < node.attributes.length;i++) {
45182 // skip empty values?
45183 if (!node.attributes.item(i).value.length) {
45186 attr.push( node.attributes.item(i).name + '="' +
45187 Roo.util.Format.htmlEncode(node.attributes.item(i).value) + '"'
45190 return attr.length ? (' ' + attr.join(' ') ) : '';
45198 * @class Roo.htmleditor.KeyEnter
45199 * Handle Enter press..
45200 * @cfg {Roo.HtmlEditorCore} core the editor.
45202 * Create a new Filter.
45203 * @param {Object} config Configuration options
45208 Roo.htmleditor.KeyEnter = function(cfg) {
45209 Roo.apply(this, cfg);
45210 // this does not actually call walk as it's really just a abstract class
45212 Roo.get(this.core.doc.body).on('keypress', this.keypress, this);
45216 Roo.htmleditor.KeyEnter.prototype = {
45220 keypress : function(e) {
45221 if (e.charCode != 13) {
45224 e.preventDefault();
45225 // https://stackoverflow.com/questions/18552336/prevent-contenteditable-adding-div-on-enter-chrome
45226 var doc = this.core.doc;
45228 var docFragment = doc.createDocumentFragment();
45231 var newEle = doc.createTextNode('\n');
45232 docFragment.appendChild(newEle);
45234 //add the br, or p, or something else
45235 newEle = doc.createElement('br');
45236 docFragment.appendChild(newEle);
45238 //make the br replace selection
45239 var range = this.core.win.getSelection().getRangeAt(0);
45240 range.deleteContents();
45241 range.insertNode(docFragment);
45243 //create a new range
45244 range = doc.createRange();
45245 range.setStartAfter(newEle);
45246 range.collapse(true);
45248 //make the cursor there
45249 var sel = this.core.win.getSelection();
45250 sel.removeAllRanges();
45251 sel.addRange(range);
45259 * @class Roo.htmleditor.Block
45260 * Base class for html editor blocks - do not use it directly .. extend it..
45261 * @cfg {DomElement} node The node to apply stuff to.
45262 * @cfg {String} friendly_name the name that appears in the context bar about this block
45263 * @cfg {Object} Context menu - see Roo.form.HtmlEditor.ToolbarContext
45266 * Create a new Filter.
45267 * @param {Object} config Configuration options
45270 Roo.htmleditor.Block = function(cfg)
45272 // do nothing .. should not be called really.
45275 Roo.htmleditor.Block.factory = function(node)
45277 var cls = Roo.htmleditor['Block' + Roo.get(node).attr('data-block')];
45278 if (typeof(cls) == 'undefined') {
45279 Roo.log("OOps missing block : " + 'Block' + Roo.get(node).attr('data-block'));
45282 return new cls({ node: node }); /// should trigger update element
45286 Roo.htmleditor.Block.prototype = {
45288 // used by context menu
45289 friendly_name : 'Image with caption',
45293 * Update a node with values from this object
45294 * @param {DomElement} node
45296 updateElement : function(node)
45298 Roo.DomHelper.update(node, this.toObject());
45301 * convert to plain HTML for calling insertAtCursor..
45303 toHTML : function()
45305 return Roo.DomHelper.markup(this.toObject());
45308 * used by readEleemnt to extract data from a node
45309 * may need improving as it's pretty basic
45311 * @param {DomElement} node
45312 * @param {String} tag - tag to find, eg. IMG ?? might be better to use DomQuery ?
45313 * @param {String} attribute (use html - for contents, or style for using next param as style)
45314 * @param {String} style the style property - eg. text-align
45316 getVal : function(node, tag, attr, style)
45319 if (n.tagName != tag.toUpperCase()) {
45320 // in theory we could do figure[3] << 3rd figure? or some more complex search..?
45321 // but kiss for now.
45322 n = node.getElementsByTagName(tag).item(0);
45324 if (attr == 'html') {
45325 return n.innerHTML;
45327 if (attr == 'style') {
45328 return Roo.get(n).getStyle(style);
45331 return Roo.get(n).attr(attr);
45335 * create a DomHelper friendly object - for use with
45336 * Roo.DomHelper.markup / overwrite / etc..
45339 toObject : function()
45344 * Read a node that has a 'data-block' property - and extract the values from it.
45345 * @param {DomElement} node - the node
45347 readElement : function(node)
45357 * <figure data-block="BlockFigure" contenteditable="false" role="group" style="text-align:left">' +
45358 <img data-name="image" src="{SRC}">' +
45359 <figcaption data-name="caption" contenteditable="true" style="text-align:left">XXXX</figcaption>
45364 -- add to document..
45365 new Roo.htmleditor.BlockFigure{
45366 image_src : 'http://www.google.com',
45369 -- load document, and search for elements of this...
45370 Roo.DomQuery.select('*[data-block])
45371 // loop each and call ctor ({node : xxx})
45372 -- html editor click
45373 ** see if parent has Element.findParent(*[data-block]);
45379 * @class Roo.htmleditor.BlockFigure
45380 * Block that has an image and a figcaption
45381 * @cfg {String} image_src the url for the image
45382 * @cfg {String} align (left|right) alignment for the block default left
45383 * @cfg {String} text_align (left|right) alignment for the text caption default left.
45384 * @cfg {String} caption the text to appear below (and in the alt tag)
45385 * @cfg {String|number} image_width the width of the image number or %?
45386 * @cfg {String|number} image_height the height of the image number or %?
45389 * Create a new Filter.
45390 * @param {Object} config Configuration options
45393 Roo.htmleditor.BlockFigure = function(cfg)
45396 this.readElement(cfg.node);
45397 this.updateElement(cfg.node);
45399 Roo.apply(this, cfg);
45401 Roo.extend(Roo.htmleditor.BlockFigure, Roo.htmleditor.Block, {
45409 text_align: 'left',
45413 // used by context menu
45414 friendly_name : 'Image with caption',
45416 context : { // ?? static really
45425 opts : [[ "left"],[ "right"]],
45430 title: "Caption Align",
45431 opts : [ [ "left"],[ "right"],[ "center"]],
45442 * create a DomHelper friendly object - for use with
45443 * Roo.DomHelper.markup / overwrite / etc..
45445 toObject : function()
45447 var d = document.createElement('div');
45448 d.innerHTML = this.caption;
45452 'data-block' : 'Figure',
45453 contenteditable : 'false',
45456 float : this.align ,
45457 width : this.width + '%'
45462 src : this.image_src,
45463 alt : d.innerText.replace(/\n/g, " "), // removeHTML..
45470 contenteditable : true,
45472 'text-align': this.text_align
45474 html : this.caption
45481 readElement : function(node)
45483 this.image_src = this.getVal(node, 'img', 'src');
45484 this.align = this.getVal(node, 'figure', 'style', 'float');
45485 this.caption = this.getVal(node, 'figcaption', 'html');
45486 this.text_align = this.getVal(node, 'figcaption', 'style','text-align');
45487 this.image_width = this.getVal(node, 'img', 'width');
45488 this.image_height = this.getVal(node, 'img', 'height');
45501 //<script type="text/javascript">
45504 * Based Ext JS Library 1.1.1
45505 * Copyright(c) 2006-2007, Ext JS, LLC.
45511 * @class Roo.HtmlEditorCore
45512 * @extends Roo.Component
45513 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
45515 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
45518 Roo.HtmlEditorCore = function(config){
45521 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
45526 * @event initialize
45527 * Fires when the editor is fully initialized (including the iframe)
45528 * @param {Roo.HtmlEditorCore} this
45533 * Fires when the editor is first receives the focus. Any insertion must wait
45534 * until after this event.
45535 * @param {Roo.HtmlEditorCore} this
45539 * @event beforesync
45540 * Fires before the textarea is updated with content from the editor iframe. Return false
45541 * to cancel the sync.
45542 * @param {Roo.HtmlEditorCore} this
45543 * @param {String} html
45547 * @event beforepush
45548 * Fires before the iframe editor is updated with content from the textarea. Return false
45549 * to cancel the push.
45550 * @param {Roo.HtmlEditorCore} this
45551 * @param {String} html
45556 * Fires when the textarea is updated with content from the editor iframe.
45557 * @param {Roo.HtmlEditorCore} this
45558 * @param {String} html
45563 * Fires when the iframe editor is updated with content from the textarea.
45564 * @param {Roo.HtmlEditorCore} this
45565 * @param {String} html
45570 * @event editorevent
45571 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
45572 * @param {Roo.HtmlEditorCore} this
45578 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
45580 // defaults : white / black...
45581 this.applyBlacklists();
45588 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
45592 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
45598 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
45603 * @cfg {Number} height (in pixels)
45607 * @cfg {Number} width (in pixels)
45612 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
45615 stylesheets: false,
45618 * @cfg {boolean} allowComments - default false - allow comments in HTML source - by default they are stripped - if you are editing email you may need this.
45620 allowComments: false,
45624 // private properties
45625 validationEvent : false,
45627 initialized : false,
45629 sourceEditMode : false,
45630 onFocus : Roo.emptyFn,
45632 hideMode:'offsets',
45636 // blacklist + whitelisted elements..
45643 * Protected method that will not generally be called directly. It
45644 * is called when the editor initializes the iframe with HTML contents. Override this method if you
45645 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
45647 getDocMarkup : function(){
45651 // inherit styels from page...??
45652 if (this.stylesheets === false) {
45654 Roo.get(document.head).select('style').each(function(node) {
45655 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
45658 Roo.get(document.head).select('link').each(function(node) {
45659 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
45662 } else if (!this.stylesheets.length) {
45664 st = '<style type="text/css">' +
45665 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
45668 for (var i in this.stylesheets) {
45669 if (typeof(this.stylesheets[i]) != 'string') {
45672 st += '<link rel="stylesheet" href="' + this.stylesheets[i] +'" type="text/css">';
45677 st += '<style type="text/css">' +
45678 'IMG { cursor: pointer } ' +
45681 var cls = 'roo-htmleditor-body';
45683 if(this.bodyCls.length){
45684 cls += ' ' + this.bodyCls;
45687 return '<html><head>' + st +
45688 //<style type="text/css">' +
45689 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
45691 ' </head><body contenteditable="true" data-enable-grammerly="true" class="' + cls + '"></body></html>';
45695 onRender : function(ct, position)
45698 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
45699 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
45702 this.el.dom.style.border = '0 none';
45703 this.el.dom.setAttribute('tabIndex', -1);
45704 this.el.addClass('x-hidden hide');
45708 if(Roo.isIE){ // fix IE 1px bogus margin
45709 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
45713 this.frameId = Roo.id();
45717 var iframe = this.owner.wrap.createChild({
45719 cls: 'form-control', // bootstrap..
45721 name: this.frameId,
45722 frameBorder : 'no',
45723 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
45728 this.iframe = iframe.dom;
45730 this.assignDocWin();
45732 this.doc.designMode = 'on';
45735 this.doc.write(this.getDocMarkup());
45739 var task = { // must defer to wait for browser to be ready
45741 //console.log("run task?" + this.doc.readyState);
45742 this.assignDocWin();
45743 if(this.doc.body || this.doc.readyState == 'complete'){
45745 this.doc.designMode="on";
45749 Roo.TaskMgr.stop(task);
45750 this.initEditor.defer(10, this);
45757 Roo.TaskMgr.start(task);
45762 onResize : function(w, h)
45764 Roo.log('resize: ' +w + ',' + h );
45765 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
45769 if(typeof w == 'number'){
45771 this.iframe.style.width = w + 'px';
45773 if(typeof h == 'number'){
45775 this.iframe.style.height = h + 'px';
45777 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
45784 * Toggles the editor between standard and source edit mode.
45785 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
45787 toggleSourceEdit : function(sourceEditMode){
45789 this.sourceEditMode = sourceEditMode === true;
45791 if(this.sourceEditMode){
45793 Roo.get(this.iframe).addClass(['x-hidden','hide', 'd-none']); //FIXME - what's the BS styles for these
45796 Roo.get(this.iframe).removeClass(['x-hidden','hide', 'd-none']);
45797 //this.iframe.className = '';
45800 //this.setSize(this.owner.wrap.getSize());
45801 //this.fireEvent('editmodechange', this, this.sourceEditMode);
45808 * Protected method that will not generally be called directly. If you need/want
45809 * custom HTML cleanup, this is the method you should override.
45810 * @param {String} html The HTML to be cleaned
45811 * return {String} The cleaned HTML
45813 cleanHtml : function(html){
45814 html = String(html);
45815 if(html.length > 5){
45816 if(Roo.isSafari){ // strip safari nonsense
45817 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
45820 if(html == ' '){
45827 * HTML Editor -> Textarea
45828 * Protected method that will not generally be called directly. Syncs the contents
45829 * of the editor iframe with the textarea.
45831 syncValue : function()
45833 Roo.log("HtmlEditorCore:syncValue (EDITOR->TEXT)");
45834 if(this.initialized){
45835 var bd = (this.doc.body || this.doc.documentElement);
45836 //this.cleanUpPaste(); -- this is done else where and causes havoc..
45838 // not sure if this is really the place for this
45839 // the blocks are synced occasionaly - since we currently dont add listeners on the blocks
45840 // this has to update attributes that get duped.. like alt and caption..
45842 Roo.each(Roo.get(this.doc.body).query('*[data-block]'), function(e) {
45843 Roo.htmleditor.Block.factory(e);
45847 var div = document.createElement('div');
45848 div.innerHTML = bd.innerHTML;
45849 // remove content editable. (blocks)
45853 new Roo.htmleditor.FilterAttributes({node : div, attrib_black: [ 'contenteditable' ] });
45855 var html = div.innerHTML;
45857 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
45858 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
45860 html = '<div style="'+m[0]+'">' + html + '</div>';
45863 html = this.cleanHtml(html);
45864 // fix up the special chars.. normaly like back quotes in word...
45865 // however we do not want to do this with chinese..
45866 html = html.replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]|[\u0080-\uFFFF]/g, function(match) {
45868 var cc = match.charCodeAt();
45870 // Get the character value, handling surrogate pairs
45871 if (match.length == 2) {
45872 // It's a surrogate pair, calculate the Unicode code point
45873 var high = match.charCodeAt(0) - 0xD800;
45874 var low = match.charCodeAt(1) - 0xDC00;
45875 cc = (high * 0x400) + low + 0x10000;
45877 (cc >= 0x4E00 && cc < 0xA000 ) ||
45878 (cc >= 0x3400 && cc < 0x4E00 ) ||
45879 (cc >= 0xf900 && cc < 0xfb00 )
45884 // No, use a numeric entity. Here we brazenly (and possibly mistakenly)
45885 return "&#" + cc + ";";
45892 if(this.owner.fireEvent('beforesync', this, html) !== false){
45893 this.el.dom.value = html;
45894 this.owner.fireEvent('sync', this, html);
45900 * TEXTAREA -> EDITABLE
45901 * Protected method that will not generally be called directly. Pushes the value of the textarea
45902 * into the iframe editor.
45904 pushValue : function()
45906 Roo.log("HtmlEditorCore:pushValue (TEXT->EDITOR)");
45907 if(this.initialized){
45908 var v = this.el.dom.value.trim();
45911 if(this.owner.fireEvent('beforepush', this, v) !== false){
45912 var d = (this.doc.body || this.doc.documentElement);
45914 //this.cleanUpPaste();
45915 this.el.dom.value = d.innerHTML;
45916 this.owner.fireEvent('push', this, v);
45919 Roo.each(Roo.get(this.doc.body).query('*[data-block]'), function(e) {
45921 Roo.htmleditor.Block.factory(e);
45924 var lc = this.doc.body.lastChild;
45925 if (lc && lc.nodeType == 1 && lc.getAttribute("contenteditable") == "false") {
45926 // add an extra line at the end.
45927 this.doc.body.appendChild(this.doc.createChild('br'));
45935 deferFocus : function(){
45936 this.focus.defer(10, this);
45940 focus : function(){
45941 if(this.win && !this.sourceEditMode){
45948 assignDocWin: function()
45950 var iframe = this.iframe;
45953 this.doc = iframe.contentWindow.document;
45954 this.win = iframe.contentWindow;
45956 // if (!Roo.get(this.frameId)) {
45959 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
45960 // this.win = Roo.get(this.frameId).dom.contentWindow;
45962 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
45966 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
45967 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
45972 initEditor : function(){
45973 //console.log("INIT EDITOR");
45974 this.assignDocWin();
45978 this.doc.designMode="on";
45980 this.doc.write(this.getDocMarkup());
45983 var dbody = (this.doc.body || this.doc.documentElement);
45984 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
45985 // this copies styles from the containing element into thsi one..
45986 // not sure why we need all of this..
45987 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
45989 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
45990 //ss['background-attachment'] = 'fixed'; // w3c
45991 dbody.bgProperties = 'fixed'; // ie
45992 //Roo.DomHelper.applyStyles(dbody, ss);
45993 Roo.EventManager.on(this.doc, {
45994 //'mousedown': this.onEditorEvent,
45995 'mouseup': this.onEditorEvent,
45996 'dblclick': this.onEditorEvent,
45997 'click': this.onEditorEvent,
45998 'keyup': this.onEditorEvent,
45999 'paste': this.onPasteEvent,
46004 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
46006 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
46007 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
46009 this.initialized = true;
46012 // initialize special key events - enter
46013 new Roo.htmleditor.KeyEnter({core : this});
46017 this.owner.fireEvent('initialize', this);
46021 onPasteEvent : function(e,v) {
46022 // default behaveiour should be our local cleanup paste? (optional?)
46023 // for simple editor - we want to hammer the paste and get rid of everything... - so over-rideable..
46024 this.owner.fireEvent('paste', e, v);
46027 onDestroy : function(){
46033 //for (var i =0; i < this.toolbars.length;i++) {
46034 // // fixme - ask toolbars for heights?
46035 // this.toolbars[i].onDestroy();
46038 //this.wrap.dom.innerHTML = '';
46039 //this.wrap.remove();
46044 onFirstFocus : function(){
46046 this.assignDocWin();
46049 this.activated = true;
46052 if(Roo.isGecko){ // prevent silly gecko errors
46054 var s = this.win.getSelection();
46055 if(!s.focusNode || s.focusNode.nodeType != 3){
46056 var r = s.getRangeAt(0);
46057 r.selectNodeContents((this.doc.body || this.doc.documentElement));
46062 this.execCmd('useCSS', true);
46063 this.execCmd('styleWithCSS', false);
46066 this.owner.fireEvent('activate', this);
46070 adjustFont: function(btn){
46071 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
46072 //if(Roo.isSafari){ // safari
46075 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
46076 if(Roo.isSafari){ // safari
46077 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
46078 v = (v < 10) ? 10 : v;
46079 v = (v > 48) ? 48 : v;
46080 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
46085 v = Math.max(1, v+adjust);
46087 this.execCmd('FontSize', v );
46090 onEditorEvent : function(e)
46092 this.owner.fireEvent('editorevent', this, e);
46093 // this.updateToolbar();
46094 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
46097 insertTag : function(tg)
46099 // could be a bit smarter... -> wrap the current selected tRoo..
46100 if (tg.toLowerCase() == 'span' ||
46101 tg.toLowerCase() == 'code' ||
46102 tg.toLowerCase() == 'sup' ||
46103 tg.toLowerCase() == 'sub'
46106 range = this.createRange(this.getSelection());
46107 var wrappingNode = this.doc.createElement(tg.toLowerCase());
46108 wrappingNode.appendChild(range.extractContents());
46109 range.insertNode(wrappingNode);
46116 this.execCmd("formatblock", tg);
46120 insertText : function(txt)
46124 var range = this.createRange();
46125 range.deleteContents();
46126 //alert(Sender.getAttribute('label'));
46128 range.insertNode(this.doc.createTextNode(txt));
46134 * Executes a Midas editor command on the editor document and performs necessary focus and
46135 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
46136 * @param {String} cmd The Midas command
46137 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
46139 relayCmd : function(cmd, value){
46141 this.execCmd(cmd, value);
46142 this.owner.fireEvent('editorevent', this);
46143 //this.updateToolbar();
46144 this.owner.deferFocus();
46148 * Executes a Midas editor command directly on the editor document.
46149 * For visual commands, you should use {@link #relayCmd} instead.
46150 * <b>This should only be called after the editor is initialized.</b>
46151 * @param {String} cmd The Midas command
46152 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
46154 execCmd : function(cmd, value){
46155 this.doc.execCommand(cmd, false, value === undefined ? null : value);
46162 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
46164 * @param {String} text | dom node..
46166 insertAtCursor : function(text)
46169 if(!this.activated){
46175 var r = this.doc.selection.createRange();
46186 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
46190 // from jquery ui (MIT licenced)
46192 var win = this.win;
46194 if (win.getSelection && win.getSelection().getRangeAt) {
46195 range = win.getSelection().getRangeAt(0);
46196 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
46197 range.insertNode(node);
46198 } else if (win.document.selection && win.document.selection.createRange) {
46199 // no firefox support
46200 var txt = typeof(text) == 'string' ? text : text.outerHTML;
46201 win.document.selection.createRange().pasteHTML(txt);
46203 // no firefox support
46204 var txt = typeof(text) == 'string' ? text : text.outerHTML;
46205 this.execCmd('InsertHTML', txt);
46214 mozKeyPress : function(e){
46216 var c = e.getCharCode(), cmd;
46219 c = String.fromCharCode(c).toLowerCase();
46233 // this.cleanUpPaste.defer(100, this);
46241 e.preventDefault();
46249 fixKeys : function(){ // load time branching for fastest keydown performance
46251 return function(e){
46252 var k = e.getKey(), r;
46255 r = this.doc.selection.createRange();
46258 r.pasteHTML('    ');
46265 r = this.doc.selection.createRange();
46267 var target = r.parentElement();
46268 if(!target || target.tagName.toLowerCase() != 'li'){
46270 r.pasteHTML('<br/>');
46276 //if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
46277 // this.cleanUpPaste.defer(100, this);
46283 }else if(Roo.isOpera){
46284 return function(e){
46285 var k = e.getKey();
46289 this.execCmd('InsertHTML','    ');
46292 //if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
46293 // this.cleanUpPaste.defer(100, this);
46298 }else if(Roo.isSafari){
46299 return function(e){
46300 var k = e.getKey();
46304 this.execCmd('InsertText','\t');
46308 //if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
46309 // this.cleanUpPaste.defer(100, this);
46317 getAllAncestors: function()
46319 var p = this.getSelectedNode();
46322 a.push(p); // push blank onto stack..
46323 p = this.getParentElement();
46327 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
46331 a.push(this.doc.body);
46335 lastSelNode : false,
46338 getSelection : function()
46340 this.assignDocWin();
46341 return Roo.isIE ? this.doc.selection : this.win.getSelection();
46344 getSelectedNode: function()
46346 // this may only work on Gecko!!!
46348 // should we cache this!!!!
46353 var range = this.createRange(this.getSelection()).cloneRange();
46356 var parent = range.parentElement();
46358 var testRange = range.duplicate();
46359 testRange.moveToElementText(parent);
46360 if (testRange.inRange(range)) {
46363 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
46366 parent = parent.parentElement;
46371 // is ancestor a text element.
46372 var ac = range.commonAncestorContainer;
46373 if (ac.nodeType == 3) {
46374 ac = ac.parentNode;
46377 var ar = ac.childNodes;
46380 var other_nodes = [];
46381 var has_other_nodes = false;
46382 for (var i=0;i<ar.length;i++) {
46383 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
46386 // fullly contained node.
46388 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
46393 // probably selected..
46394 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
46395 other_nodes.push(ar[i]);
46399 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
46404 has_other_nodes = true;
46406 if (!nodes.length && other_nodes.length) {
46407 nodes= other_nodes;
46409 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
46415 createRange: function(sel)
46417 // this has strange effects when using with
46418 // top toolbar - not sure if it's a great idea.
46419 //this.editor.contentWindow.focus();
46420 if (typeof sel != "undefined") {
46422 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
46424 return this.doc.createRange();
46427 return this.doc.createRange();
46430 getParentElement: function()
46433 this.assignDocWin();
46434 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
46436 var range = this.createRange(sel);
46439 var p = range.commonAncestorContainer;
46440 while (p.nodeType == 3) { // text node
46451 * Range intersection.. the hard stuff...
46455 * [ -- selected range --- ]
46459 * if end is before start or hits it. fail.
46460 * if start is after end or hits it fail.
46462 * if either hits (but other is outside. - then it's not
46468 // @see http://www.thismuchiknow.co.uk/?p=64.
46469 rangeIntersectsNode : function(range, node)
46471 var nodeRange = node.ownerDocument.createRange();
46473 nodeRange.selectNode(node);
46475 nodeRange.selectNodeContents(node);
46478 var rangeStartRange = range.cloneRange();
46479 rangeStartRange.collapse(true);
46481 var rangeEndRange = range.cloneRange();
46482 rangeEndRange.collapse(false);
46484 var nodeStartRange = nodeRange.cloneRange();
46485 nodeStartRange.collapse(true);
46487 var nodeEndRange = nodeRange.cloneRange();
46488 nodeEndRange.collapse(false);
46490 return rangeStartRange.compareBoundaryPoints(
46491 Range.START_TO_START, nodeEndRange) == -1 &&
46492 rangeEndRange.compareBoundaryPoints(
46493 Range.START_TO_START, nodeStartRange) == 1;
46497 rangeCompareNode : function(range, node)
46499 var nodeRange = node.ownerDocument.createRange();
46501 nodeRange.selectNode(node);
46503 nodeRange.selectNodeContents(node);
46507 range.collapse(true);
46509 nodeRange.collapse(true);
46511 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
46512 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
46514 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
46516 var nodeIsBefore = ss == 1;
46517 var nodeIsAfter = ee == -1;
46519 if (nodeIsBefore && nodeIsAfter) {
46522 if (!nodeIsBefore && nodeIsAfter) {
46523 return 1; //right trailed.
46526 if (nodeIsBefore && !nodeIsAfter) {
46527 return 2; // left trailed.
46533 // private? - in a new class?
46534 cleanUpPaste : function()
46536 // cleans up the whole document..
46537 Roo.log('cleanuppaste');
46539 this.cleanUpChild(this.doc.body);
46540 var clean = this.cleanWordChars(this.doc.body.innerHTML);
46541 if (clean != this.doc.body.innerHTML) {
46542 this.doc.body.innerHTML = clean;
46547 cleanWordChars : function(input) {// change the chars to hex code
46548 var he = Roo.HtmlEditorCore;
46550 var output = input;
46551 Roo.each(he.swapCodes, function(sw) {
46552 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
46554 output = output.replace(swapper, sw[1]);
46564 cleanUpChild : function (node)
46567 new Roo.htmleditor.FilterComment({node : node});
46568 new Roo.htmleditor.FilterAttributes({
46570 attrib_black : this.ablack,
46571 attrib_clean : this.aclean,
46572 style_white : this.cwhite,
46573 style_black : this.cblack
46575 new Roo.htmleditor.FilterBlack({ node : node, tag : this.black});
46576 new Roo.htmleditor.FilterKeepChildren({node : node, tag : this.tag_remove} );
46582 * Clean up MS wordisms...
46583 * @deprecated - use filter directly
46585 cleanWord : function(node)
46587 new Roo.htmleditor.FilterWord({ node : node ? node : this.doc.body });
46594 * @deprecated - use filters
46596 cleanTableWidths : function(node)
46598 new Roo.htmleditor.FilterTableWidth({ node : node ? node : this.doc.body});
46605 applyBlacklists : function()
46607 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
46608 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
46610 this.aclean = typeof(this.owner.aclean) != 'undefined' && this.owner.aclean ? this.owner.aclean : Roo.HtmlEditorCore.aclean;
46611 this.ablack = typeof(this.owner.ablack) != 'undefined' && this.owner.ablack ? this.owner.ablack : Roo.HtmlEditorCore.ablack;
46612 this.tag_remove = typeof(this.owner.tag_remove) != 'undefined' && this.owner.tag_remove ? this.owner.tag_remove : Roo.HtmlEditorCore.tag_remove;
46616 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
46617 if (b.indexOf(tag) > -1) {
46620 this.white.push(tag);
46624 Roo.each(w, function(tag) {
46625 if (b.indexOf(tag) > -1) {
46628 if (this.white.indexOf(tag) > -1) {
46631 this.white.push(tag);
46636 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
46637 if (w.indexOf(tag) > -1) {
46640 this.black.push(tag);
46644 Roo.each(b, function(tag) {
46645 if (w.indexOf(tag) > -1) {
46648 if (this.black.indexOf(tag) > -1) {
46651 this.black.push(tag);
46656 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
46657 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
46661 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
46662 if (b.indexOf(tag) > -1) {
46665 this.cwhite.push(tag);
46669 Roo.each(w, function(tag) {
46670 if (b.indexOf(tag) > -1) {
46673 if (this.cwhite.indexOf(tag) > -1) {
46676 this.cwhite.push(tag);
46681 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
46682 if (w.indexOf(tag) > -1) {
46685 this.cblack.push(tag);
46689 Roo.each(b, function(tag) {
46690 if (w.indexOf(tag) > -1) {
46693 if (this.cblack.indexOf(tag) > -1) {
46696 this.cblack.push(tag);
46701 setStylesheets : function(stylesheets)
46703 if(typeof(stylesheets) == 'string'){
46704 Roo.get(this.iframe.contentDocument.head).createChild({
46706 rel : 'stylesheet',
46715 Roo.each(stylesheets, function(s) {
46720 Roo.get(_this.iframe.contentDocument.head).createChild({
46722 rel : 'stylesheet',
46731 removeStylesheets : function()
46735 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
46740 setStyle : function(style)
46742 Roo.get(this.iframe.contentDocument.head).createChild({
46751 // hide stuff that is not compatible
46765 * @event specialkey
46769 * @cfg {String} fieldClass @hide
46772 * @cfg {String} focusClass @hide
46775 * @cfg {String} autoCreate @hide
46778 * @cfg {String} inputType @hide
46781 * @cfg {String} invalidClass @hide
46784 * @cfg {String} invalidText @hide
46787 * @cfg {String} msgFx @hide
46790 * @cfg {String} validateOnBlur @hide
46794 Roo.HtmlEditorCore.white = [
46795 'area', 'br', 'img', 'input', 'hr', 'wbr',
46797 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
46798 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
46799 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
46800 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
46801 'table', 'ul', 'xmp',
46803 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
46806 'dir', 'menu', 'ol', 'ul', 'dl',
46812 Roo.HtmlEditorCore.black = [
46813 // 'embed', 'object', // enable - backend responsiblity to clean thiese
46815 'base', 'basefont', 'bgsound', 'blink', 'body',
46816 'frame', 'frameset', 'head', 'html', 'ilayer',
46817 'iframe', 'layer', 'link', 'meta', 'object',
46818 'script', 'style' ,'title', 'xml' // clean later..
46820 Roo.HtmlEditorCore.clean = [
46821 'script', 'style', 'title', 'xml'
46823 Roo.HtmlEditorCore.tag_remove = [
46828 Roo.HtmlEditorCore.ablack = [
46832 Roo.HtmlEditorCore.aclean = [
46833 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
46837 Roo.HtmlEditorCore.pwhite= [
46838 'http', 'https', 'mailto'
46841 // white listed style attributes.
46842 Roo.HtmlEditorCore.cwhite= [
46843 // 'text-align', /// default is to allow most things..
46849 // black listed style attributes.
46850 Roo.HtmlEditorCore.cblack= [
46851 // 'font-size' -- this can be set by the project
46855 Roo.HtmlEditorCore.swapCodes =[
46856 [ 8211, "–" ],
46857 [ 8212, "—" ],
46866 //<script type="text/javascript">
46869 * Ext JS Library 1.1.1
46870 * Copyright(c) 2006-2007, Ext JS, LLC.
46876 Roo.form.HtmlEditor = function(config){
46880 Roo.form.HtmlEditor.superclass.constructor.call(this, config);
46882 if (!this.toolbars) {
46883 this.toolbars = [];
46885 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
46891 * @class Roo.form.HtmlEditor
46892 * @extends Roo.form.Field
46893 * Provides a lightweight HTML Editor component.
46895 * This has been tested on Fireforx / Chrome.. IE may not be so great..
46897 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
46898 * supported by this editor.</b><br/><br/>
46899 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
46900 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
46902 Roo.extend(Roo.form.HtmlEditor, Roo.form.Field, {
46904 * @cfg {Boolean} clearUp
46908 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
46913 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
46918 * @cfg {Number} height (in pixels)
46922 * @cfg {Number} width (in pixels)
46927 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets - this is usally a good idea rootURL + '/roojs1/css/undoreset.css', .
46930 stylesheets: false,
46934 * @cfg {Array} blacklist of css styles style attributes (blacklist overrides whitelist)
46939 * @cfg {Array} whitelist of css styles style attributes (blacklist overrides whitelist)
46945 * @cfg {Array} blacklist of html tags - in addition to standard blacklist.
46950 * @cfg {Array} whitelist of html tags - in addition to statndard whitelist
46955 * @cfg {boolean} allowComments - default false - allow comments in HTML source - by default they are stripped - if you are editing email you may need this.
46957 allowComments: false,
46959 * @cfg {string} bodyCls- default '' default classes to add to body of editable area - usually undoreset is a good start..
46968 // private properties
46969 validationEvent : false,
46971 initialized : false,
46974 onFocus : Roo.emptyFn,
46976 hideMode:'offsets',
46978 actionMode : 'container', // defaults to hiding it...
46980 defaultAutoCreate : { // modified by initCompnoent..
46982 style:"width:500px;height:300px;",
46983 autocomplete: "new-password"
46987 initComponent : function(){
46990 * @event initialize
46991 * Fires when the editor is fully initialized (including the iframe)
46992 * @param {HtmlEditor} this
46997 * Fires when the editor is first receives the focus. Any insertion must wait
46998 * until after this event.
46999 * @param {HtmlEditor} this
47003 * @event beforesync
47004 * Fires before the textarea is updated with content from the editor iframe. Return false
47005 * to cancel the sync.
47006 * @param {HtmlEditor} this
47007 * @param {String} html
47011 * @event beforepush
47012 * Fires before the iframe editor is updated with content from the textarea. Return false
47013 * to cancel the push.
47014 * @param {HtmlEditor} this
47015 * @param {String} html
47020 * Fires when the textarea is updated with content from the editor iframe.
47021 * @param {HtmlEditor} this
47022 * @param {String} html
47027 * Fires when the iframe editor is updated with content from the textarea.
47028 * @param {HtmlEditor} this
47029 * @param {String} html
47033 * @event editmodechange
47034 * Fires when the editor switches edit modes
47035 * @param {HtmlEditor} this
47036 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
47038 editmodechange: true,
47040 * @event editorevent
47041 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
47042 * @param {HtmlEditor} this
47046 * @event firstfocus
47047 * Fires when on first focus - needed by toolbars..
47048 * @param {HtmlEditor} this
47053 * Auto save the htmlEditor value as a file into Events
47054 * @param {HtmlEditor} this
47058 * @event savedpreview
47059 * preview the saved version of htmlEditor
47060 * @param {HtmlEditor} this
47062 savedpreview: true,
47065 * @event stylesheetsclick
47066 * Fires when press the Sytlesheets button
47067 * @param {Roo.HtmlEditorCore} this
47069 stylesheetsclick: true,
47072 * Fires when press user pastes into the editor
47073 * @param {Roo.HtmlEditorCore} this
47077 this.defaultAutoCreate = {
47079 style:'width: ' + this.width + 'px;height: ' + this.height + 'px;',
47080 autocomplete: "new-password"
47085 * Protected method that will not generally be called directly. It
47086 * is called when the editor creates its toolbar. Override this method if you need to
47087 * add custom toolbar buttons.
47088 * @param {HtmlEditor} editor
47090 createToolbar : function(editor){
47091 Roo.log("create toolbars");
47092 if (!editor.toolbars || !editor.toolbars.length) {
47093 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
47096 for (var i =0 ; i < editor.toolbars.length;i++) {
47097 editor.toolbars[i] = Roo.factory(
47098 typeof(editor.toolbars[i]) == 'string' ?
47099 { xtype: editor.toolbars[i]} : editor.toolbars[i],
47100 Roo.form.HtmlEditor);
47101 editor.toolbars[i].init(editor);
47109 onRender : function(ct, position)
47112 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
47114 this.wrap = this.el.wrap({
47115 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
47118 this.editorcore.onRender(ct, position);
47120 if (this.resizable) {
47121 this.resizeEl = new Roo.Resizable(this.wrap, {
47125 minHeight : this.height,
47126 height: this.height,
47127 handles : this.resizable,
47130 resize : function(r, w, h) {
47131 _t.onResize(w,h); // -something
47137 this.createToolbar(this);
47141 this.setSize(this.wrap.getSize());
47143 if (this.resizeEl) {
47144 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
47145 // should trigger onReize..
47148 this.keyNav = new Roo.KeyNav(this.el, {
47150 "tab" : function(e){
47151 e.preventDefault();
47153 var value = this.getValue();
47155 var start = this.el.dom.selectionStart;
47156 var end = this.el.dom.selectionEnd;
47160 this.setValue(value.substring(0, start) + "\t" + value.substring(end));
47161 this.el.dom.setSelectionRange(end + 1, end + 1);
47165 var f = value.substring(0, start).split("\t");
47167 if(f.pop().length != 0){
47171 this.setValue(f.join("\t") + value.substring(end));
47172 this.el.dom.setSelectionRange(start - 1, start - 1);
47176 "home" : function(e){
47177 e.preventDefault();
47179 var curr = this.el.dom.selectionStart;
47180 var lines = this.getValue().split("\n");
47187 this.el.dom.setSelectionRange(0, 0);
47193 for (var i = 0; i < lines.length;i++) {
47194 pos += lines[i].length;
47204 pos -= lines[i].length;
47210 this.el.dom.setSelectionRange(pos, pos);
47214 this.el.dom.selectionStart = pos;
47215 this.el.dom.selectionEnd = curr;
47218 "end" : function(e){
47219 e.preventDefault();
47221 var curr = this.el.dom.selectionStart;
47222 var lines = this.getValue().split("\n");
47229 this.el.dom.setSelectionRange(this.getValue().length, this.getValue().length);
47235 for (var i = 0; i < lines.length;i++) {
47237 pos += lines[i].length;
47251 this.el.dom.setSelectionRange(pos, pos);
47255 this.el.dom.selectionStart = curr;
47256 this.el.dom.selectionEnd = pos;
47261 doRelay : function(foo, bar, hname){
47262 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
47268 // if(this.autosave && this.w){
47269 // this.autoSaveFn = setInterval(this.autosave, 1000);
47274 onResize : function(w, h)
47276 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
47281 if(typeof w == 'number'){
47282 var aw = w - this.wrap.getFrameWidth('lr');
47283 this.el.setWidth(this.adjustWidth('textarea', aw));
47286 if(typeof h == 'number'){
47288 for (var i =0; i < this.toolbars.length;i++) {
47289 // fixme - ask toolbars for heights?
47290 tbh += this.toolbars[i].tb.el.getHeight();
47291 if (this.toolbars[i].footer) {
47292 tbh += this.toolbars[i].footer.el.getHeight();
47299 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
47300 ah -= 5; // knock a few pixes off for look..
47302 this.el.setHeight(this.adjustWidth('textarea', ah));
47306 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
47307 this.editorcore.onResize(ew,eh);
47312 * Toggles the editor between standard and source edit mode.
47313 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
47315 toggleSourceEdit : function(sourceEditMode)
47317 this.editorcore.toggleSourceEdit(sourceEditMode);
47319 if(this.editorcore.sourceEditMode){
47320 Roo.log('editor - showing textarea');
47323 // Roo.log(this.syncValue());
47324 this.editorcore.syncValue();
47325 this.el.removeClass('x-hidden');
47326 this.el.dom.removeAttribute('tabIndex');
47328 this.el.dom.scrollTop = 0;
47331 for (var i = 0; i < this.toolbars.length; i++) {
47332 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
47333 this.toolbars[i].tb.hide();
47334 this.toolbars[i].footer.hide();
47339 Roo.log('editor - hiding textarea');
47341 // Roo.log(this.pushValue());
47342 this.editorcore.pushValue();
47344 this.el.addClass('x-hidden');
47345 this.el.dom.setAttribute('tabIndex', -1);
47347 for (var i = 0; i < this.toolbars.length; i++) {
47348 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
47349 this.toolbars[i].tb.show();
47350 this.toolbars[i].footer.show();
47354 //this.deferFocus();
47357 this.setSize(this.wrap.getSize());
47358 this.onResize(this.wrap.getSize().width, this.wrap.getSize().height);
47360 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
47363 // private (for BoxComponent)
47364 adjustSize : Roo.BoxComponent.prototype.adjustSize,
47366 // private (for BoxComponent)
47367 getResizeEl : function(){
47371 // private (for BoxComponent)
47372 getPositionEl : function(){
47377 initEvents : function(){
47378 this.originalValue = this.getValue();
47382 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
47385 markInvalid : Roo.emptyFn,
47387 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
47390 clearInvalid : Roo.emptyFn,
47392 setValue : function(v){
47393 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
47394 this.editorcore.pushValue();
47399 deferFocus : function(){
47400 this.focus.defer(10, this);
47404 focus : function(){
47405 this.editorcore.focus();
47411 onDestroy : function(){
47417 for (var i =0; i < this.toolbars.length;i++) {
47418 // fixme - ask toolbars for heights?
47419 this.toolbars[i].onDestroy();
47422 this.wrap.dom.innerHTML = '';
47423 this.wrap.remove();
47428 onFirstFocus : function(){
47429 //Roo.log("onFirstFocus");
47430 this.editorcore.onFirstFocus();
47431 for (var i =0; i < this.toolbars.length;i++) {
47432 this.toolbars[i].onFirstFocus();
47438 syncValue : function()
47440 this.editorcore.syncValue();
47443 pushValue : function()
47445 this.editorcore.pushValue();
47448 setStylesheets : function(stylesheets)
47450 this.editorcore.setStylesheets(stylesheets);
47453 removeStylesheets : function()
47455 this.editorcore.removeStylesheets();
47459 // hide stuff that is not compatible
47473 * @event specialkey
47477 * @cfg {String} fieldClass @hide
47480 * @cfg {String} focusClass @hide
47483 * @cfg {String} autoCreate @hide
47486 * @cfg {String} inputType @hide
47489 * @cfg {String} invalidClass @hide
47492 * @cfg {String} invalidText @hide
47495 * @cfg {String} msgFx @hide
47498 * @cfg {String} validateOnBlur @hide
47502 // <script type="text/javascript">
47505 * Ext JS Library 1.1.1
47506 * Copyright(c) 2006-2007, Ext JS, LLC.
47512 * @class Roo.form.HtmlEditorToolbar1
47517 new Roo.form.HtmlEditor({
47520 new Roo.form.HtmlEditorToolbar1({
47521 disable : { fonts: 1 , format: 1, ..., ... , ...],
47527 * @cfg {Object} disable List of elements to disable..
47528 * @cfg {Array} btns List of additional buttons.
47532 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
47535 Roo.form.HtmlEditor.ToolbarStandard = function(config)
47538 Roo.apply(this, config);
47540 // default disabled, based on 'good practice'..
47541 this.disable = this.disable || {};
47542 Roo.applyIf(this.disable, {
47545 specialElements : true
47549 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
47550 // dont call parent... till later.
47553 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
47560 editorcore : false,
47562 * @cfg {Object} disable List of toolbar elements to disable
47569 * @cfg {String} createLinkText The default text for the create link prompt
47571 createLinkText : 'Please enter the URL for the link:',
47573 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
47575 defaultLinkValue : 'http:/'+'/',
47579 * @cfg {Array} fontFamilies An array of available font families
47597 // "á" , ?? a acute?
47602 "°" // , // degrees
47604 // "é" , // e ecute
47605 // "ú" , // u ecute?
47608 specialElements : [
47610 text: "Insert Table",
47613 ihtml : '<table><tr><td>Cell</td></tr></table>'
47617 text: "Insert Image",
47620 ihtml : '<img src="about:blank"/>'
47629 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
47630 "input:submit", "input:button", "select", "textarea", "label" ],
47633 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
47635 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"],
47644 * @cfg {String} defaultFont default font to use.
47646 defaultFont: 'tahoma',
47648 fontSelect : false,
47651 formatCombo : false,
47653 init : function(editor)
47655 this.editor = editor;
47656 this.editorcore = editor.editorcore ? editor.editorcore : editor;
47657 var editorcore = this.editorcore;
47661 var fid = editorcore.frameId;
47663 function btn(id, toggle, handler){
47664 var xid = fid + '-'+ id ;
47668 cls : 'x-btn-icon x-edit-'+id,
47669 enableToggle:toggle !== false,
47670 scope: _t, // was editor...
47671 handler:handler||_t.relayBtnCmd,
47672 clickEvent:'mousedown',
47673 tooltip: etb.buttonTips[id] || undefined, ///tips ???
47680 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
47682 // stop form submits
47683 tb.el.on('click', function(e){
47684 e.preventDefault(); // what does this do?
47687 if(!this.disable.font) { // && !Roo.isSafari){
47688 /* why no safari for fonts
47689 editor.fontSelect = tb.el.createChild({
47692 cls:'x-font-select',
47693 html: this.createFontOptions()
47696 editor.fontSelect.on('change', function(){
47697 var font = editor.fontSelect.dom.value;
47698 editor.relayCmd('fontname', font);
47699 editor.deferFocus();
47703 editor.fontSelect.dom,
47709 if(!this.disable.formats){
47710 this.formatCombo = new Roo.form.ComboBox({
47711 store: new Roo.data.SimpleStore({
47714 data : this.formats // from states.js
47718 //autoCreate : {tag: "div", size: "20"},
47719 displayField:'tag',
47723 triggerAction: 'all',
47724 emptyText:'Add tag',
47725 selectOnFocus:true,
47728 'select': function(c, r, i) {
47729 editorcore.insertTag(r.get('tag'));
47735 tb.addField(this.formatCombo);
47739 if(!this.disable.format){
47744 btn('strikethrough')
47747 if(!this.disable.fontSize){
47752 btn('increasefontsize', false, editorcore.adjustFont),
47753 btn('decreasefontsize', false, editorcore.adjustFont)
47758 if(!this.disable.colors){
47761 id:editorcore.frameId +'-forecolor',
47762 cls:'x-btn-icon x-edit-forecolor',
47763 clickEvent:'mousedown',
47764 tooltip: this.buttonTips['forecolor'] || undefined,
47766 menu : new Roo.menu.ColorMenu({
47767 allowReselect: true,
47768 focus: Roo.emptyFn,
47771 selectHandler: function(cp, color){
47772 editorcore.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
47773 editor.deferFocus();
47776 clickEvent:'mousedown'
47779 id:editorcore.frameId +'backcolor',
47780 cls:'x-btn-icon x-edit-backcolor',
47781 clickEvent:'mousedown',
47782 tooltip: this.buttonTips['backcolor'] || undefined,
47784 menu : new Roo.menu.ColorMenu({
47785 focus: Roo.emptyFn,
47788 allowReselect: true,
47789 selectHandler: function(cp, color){
47791 editorcore.execCmd('useCSS', false);
47792 editorcore.execCmd('hilitecolor', color);
47793 editorcore.execCmd('useCSS', true);
47794 editor.deferFocus();
47796 editorcore.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
47797 Roo.isSafari || Roo.isIE ? '#'+color : color);
47798 editor.deferFocus();
47802 clickEvent:'mousedown'
47807 // now add all the items...
47810 if(!this.disable.alignments){
47813 btn('justifyleft'),
47814 btn('justifycenter'),
47815 btn('justifyright')
47819 //if(!Roo.isSafari){
47820 if(!this.disable.links){
47823 btn('createlink', false, this.createLink) /// MOVE TO HERE?!!?!?!?!
47827 if(!this.disable.lists){
47830 btn('insertorderedlist'),
47831 btn('insertunorderedlist')
47834 if(!this.disable.sourceEdit){
47837 btn('sourceedit', true, function(btn){
47838 this.toggleSourceEdit(btn.pressed);
47845 // special menu.. - needs to be tidied up..
47846 if (!this.disable.special) {
47849 cls: 'x-edit-none',
47855 for (var i =0; i < this.specialChars.length; i++) {
47856 smenu.menu.items.push({
47858 html: this.specialChars[i],
47859 handler: function(a,b) {
47860 editorcore.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
47861 //editor.insertAtCursor(a.html);
47875 if (!this.disable.cleanStyles) {
47877 cls: 'x-btn-icon x-btn-clear',
47883 for (var i =0; i < this.cleanStyles.length; i++) {
47884 cmenu.menu.items.push({
47885 actiontype : this.cleanStyles[i],
47886 html: 'Remove ' + this.cleanStyles[i],
47887 handler: function(a,b) {
47890 var c = Roo.get(editorcore.doc.body);
47891 c.select('[style]').each(function(s) {
47892 s.dom.style.removeProperty(a.actiontype);
47894 editorcore.syncValue();
47899 cmenu.menu.items.push({
47900 actiontype : 'tablewidths',
47901 html: 'Remove Table Widths',
47902 handler: function(a,b) {
47903 editorcore.cleanTableWidths();
47904 editorcore.syncValue();
47908 cmenu.menu.items.push({
47909 actiontype : 'word',
47910 html: 'Remove MS Word Formating',
47911 handler: function(a,b) {
47912 editorcore.cleanWord();
47913 editorcore.syncValue();
47918 cmenu.menu.items.push({
47919 actiontype : 'all',
47920 html: 'Remove All Styles',
47921 handler: function(a,b) {
47923 var c = Roo.get(editorcore.doc.body);
47924 c.select('[style]').each(function(s) {
47925 s.dom.removeAttribute('style');
47927 editorcore.syncValue();
47932 cmenu.menu.items.push({
47933 actiontype : 'all',
47934 html: 'Remove All CSS Classes',
47935 handler: function(a,b) {
47937 var c = Roo.get(editorcore.doc.body);
47938 c.select('[class]').each(function(s) {
47939 s.dom.removeAttribute('class');
47941 editorcore.cleanWord();
47942 editorcore.syncValue();
47947 cmenu.menu.items.push({
47948 actiontype : 'tidy',
47949 html: 'Tidy HTML Source',
47950 handler: function(a,b) {
47951 new Roo.htmleditor.Tidy(editorcore.doc.body);
47952 editorcore.syncValue();
47961 if (!this.disable.specialElements) {
47964 cls: 'x-edit-none',
47969 for (var i =0; i < this.specialElements.length; i++) {
47970 semenu.menu.items.push(
47972 handler: function(a,b) {
47973 editor.insertAtCursor(this.ihtml);
47975 }, this.specialElements[i])
47987 for(var i =0; i< this.btns.length;i++) {
47988 var b = Roo.factory(this.btns[i],Roo.form);
47989 b.cls = 'x-edit-none';
47991 if(typeof(this.btns[i].cls) != 'undefined' && this.btns[i].cls.indexOf('x-init-enable') !== -1){
47992 b.cls += ' x-init-enable';
47995 b.scope = editorcore;
48003 // disable everything...
48005 this.tb.items.each(function(item){
48008 item.id != editorcore.frameId+ '-sourceedit' &&
48009 (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)
48015 this.rendered = true;
48017 // the all the btns;
48018 editor.on('editorevent', this.updateToolbar, this);
48019 // other toolbars need to implement this..
48020 //editor.on('editmodechange', this.updateToolbar, this);
48024 relayBtnCmd : function(btn) {
48025 this.editorcore.relayCmd(btn.cmd);
48027 // private used internally
48028 createLink : function(){
48029 Roo.log("create link?");
48030 var url = prompt(this.createLinkText, this.defaultLinkValue);
48031 if(url && url != 'http:/'+'/'){
48032 this.editorcore.relayCmd('createlink', url);
48038 * Protected method that will not generally be called directly. It triggers
48039 * a toolbar update by reading the markup state of the current selection in the editor.
48041 updateToolbar: function(){
48043 if(!this.editorcore.activated){
48044 this.editor.onFirstFocus();
48048 var btns = this.tb.items.map,
48049 doc = this.editorcore.doc,
48050 frameId = this.editorcore.frameId;
48052 if(!this.disable.font && !Roo.isSafari){
48054 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
48055 if(name != this.fontSelect.dom.value){
48056 this.fontSelect.dom.value = name;
48060 if(!this.disable.format){
48061 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
48062 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
48063 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
48064 btns[frameId + '-strikethrough'].toggle(doc.queryCommandState('strikethrough'));
48066 if(!this.disable.alignments){
48067 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
48068 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
48069 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
48071 if(!Roo.isSafari && !this.disable.lists){
48072 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
48073 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
48076 var ans = this.editorcore.getAllAncestors();
48077 if (this.formatCombo) {
48080 var store = this.formatCombo.store;
48081 this.formatCombo.setValue("");
48082 for (var i =0; i < ans.length;i++) {
48083 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
48085 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
48093 // hides menus... - so this cant be on a menu...
48094 Roo.menu.MenuMgr.hideAll();
48096 //this.editorsyncValue();
48100 createFontOptions : function(){
48101 var buf = [], fs = this.fontFamilies, ff, lc;
48105 for(var i = 0, len = fs.length; i< len; i++){
48107 lc = ff.toLowerCase();
48109 '<option value="',lc,'" style="font-family:',ff,';"',
48110 (this.defaultFont == lc ? ' selected="true">' : '>'),
48115 return buf.join('');
48118 toggleSourceEdit : function(sourceEditMode){
48120 Roo.log("toolbar toogle");
48121 if(sourceEditMode === undefined){
48122 sourceEditMode = !this.sourceEditMode;
48124 this.sourceEditMode = sourceEditMode === true;
48125 var btn = this.tb.items.get(this.editorcore.frameId +'-sourceedit');
48126 // just toggle the button?
48127 if(btn.pressed !== this.sourceEditMode){
48128 btn.toggle(this.sourceEditMode);
48132 if(sourceEditMode){
48133 Roo.log("disabling buttons");
48134 this.tb.items.each(function(item){
48135 if(item.cmd != 'sourceedit' && (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)){
48141 Roo.log("enabling buttons");
48142 if(this.editorcore.initialized){
48143 this.tb.items.each(function(item){
48149 Roo.log("calling toggole on editor");
48150 // tell the editor that it's been pressed..
48151 this.editor.toggleSourceEdit(sourceEditMode);
48155 * Object collection of toolbar tooltips for the buttons in the editor. The key
48156 * is the command id associated with that button and the value is a valid QuickTips object.
48161 title: 'Bold (Ctrl+B)',
48162 text: 'Make the selected text bold.',
48163 cls: 'x-html-editor-tip'
48166 title: 'Italic (Ctrl+I)',
48167 text: 'Make the selected text italic.',
48168 cls: 'x-html-editor-tip'
48176 title: 'Bold (Ctrl+B)',
48177 text: 'Make the selected text bold.',
48178 cls: 'x-html-editor-tip'
48181 title: 'Italic (Ctrl+I)',
48182 text: 'Make the selected text italic.',
48183 cls: 'x-html-editor-tip'
48186 title: 'Underline (Ctrl+U)',
48187 text: 'Underline the selected text.',
48188 cls: 'x-html-editor-tip'
48191 title: 'Strikethrough',
48192 text: 'Strikethrough the selected text.',
48193 cls: 'x-html-editor-tip'
48195 increasefontsize : {
48196 title: 'Grow Text',
48197 text: 'Increase the font size.',
48198 cls: 'x-html-editor-tip'
48200 decreasefontsize : {
48201 title: 'Shrink Text',
48202 text: 'Decrease the font size.',
48203 cls: 'x-html-editor-tip'
48206 title: 'Text Highlight Color',
48207 text: 'Change the background color of the selected text.',
48208 cls: 'x-html-editor-tip'
48211 title: 'Font Color',
48212 text: 'Change the color of the selected text.',
48213 cls: 'x-html-editor-tip'
48216 title: 'Align Text Left',
48217 text: 'Align text to the left.',
48218 cls: 'x-html-editor-tip'
48221 title: 'Center Text',
48222 text: 'Center text in the editor.',
48223 cls: 'x-html-editor-tip'
48226 title: 'Align Text Right',
48227 text: 'Align text to the right.',
48228 cls: 'x-html-editor-tip'
48230 insertunorderedlist : {
48231 title: 'Bullet List',
48232 text: 'Start a bulleted list.',
48233 cls: 'x-html-editor-tip'
48235 insertorderedlist : {
48236 title: 'Numbered List',
48237 text: 'Start a numbered list.',
48238 cls: 'x-html-editor-tip'
48241 title: 'Hyperlink',
48242 text: 'Make the selected text a hyperlink.',
48243 cls: 'x-html-editor-tip'
48246 title: 'Source Edit',
48247 text: 'Switch to source editing mode.',
48248 cls: 'x-html-editor-tip'
48252 onDestroy : function(){
48255 this.tb.items.each(function(item){
48257 item.menu.removeAll();
48259 item.menu.el.destroy();
48267 onFirstFocus: function() {
48268 this.tb.items.each(function(item){
48277 // <script type="text/javascript">
48280 * Ext JS Library 1.1.1
48281 * Copyright(c) 2006-2007, Ext JS, LLC.
48288 * @class Roo.form.HtmlEditor.ToolbarContext
48293 new Roo.form.HtmlEditor({
48296 { xtype: 'ToolbarStandard', styles : {} }
48297 { xtype: 'ToolbarContext', disable : {} }
48303 * @config : {Object} disable List of elements to disable.. (not done yet.)
48304 * @config : {Object} styles Map of styles available.
48308 Roo.form.HtmlEditor.ToolbarContext = function(config)
48311 Roo.apply(this, config);
48312 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
48313 // dont call parent... till later.
48314 this.styles = this.styles || {};
48319 Roo.form.HtmlEditor.ToolbarContext.types = {
48331 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
48353 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
48405 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
48410 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
48420 style : 'fontFamily',
48421 displayField: 'display',
48422 optname : 'font-family',
48471 // should we really allow this??
48472 // should this just be
48484 style : 'fontFamily',
48485 displayField: 'display',
48486 optname : 'font-family',
48493 style : 'fontFamily',
48494 displayField: 'display',
48495 optname : 'font-family',
48502 style : 'fontFamily',
48503 displayField: 'display',
48504 optname : 'font-family',
48515 // this should be configurable.. - you can either set it up using stores, or modify options somehwere..
48516 Roo.form.HtmlEditor.ToolbarContext.stores = false;
48518 Roo.form.HtmlEditor.ToolbarContext.options = {
48520 [ 'Helvetica,Arial,sans-serif', 'Helvetica'],
48521 [ 'Courier New', 'Courier New'],
48522 [ 'Tahoma', 'Tahoma'],
48523 [ 'Times New Roman,serif', 'Times'],
48524 [ 'Verdana','Verdana' ]
48528 // fixme - these need to be configurable..
48531 //Roo.form.HtmlEditor.ToolbarContext.types
48534 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
48541 editorcore : false,
48543 * @cfg {Object} disable List of toolbar elements to disable
48548 * @cfg {Object} styles List of styles
48549 * eg. { '*' : [ 'headline' ] , 'TD' : [ 'underline', 'double-underline' ] }
48551 * These must be defined in the page, so they get rendered correctly..
48562 init : function(editor)
48564 this.editor = editor;
48565 this.editorcore = editor.editorcore ? editor.editorcore : editor;
48566 var editorcore = this.editorcore;
48568 var fid = editorcore.frameId;
48570 function btn(id, toggle, handler){
48571 var xid = fid + '-'+ id ;
48575 cls : 'x-btn-icon x-edit-'+id,
48576 enableToggle:toggle !== false,
48577 scope: editorcore, // was editor...
48578 handler:handler||editorcore.relayBtnCmd,
48579 clickEvent:'mousedown',
48580 tooltip: etb.buttonTips[id] || undefined, ///tips ???
48584 // create a new element.
48585 var wdiv = editor.wrap.createChild({
48587 }, editor.wrap.dom.firstChild.nextSibling, true);
48589 // can we do this more than once??
48591 // stop form submits
48594 // disable everything...
48595 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
48596 this.toolbars = {};
48598 for (var i in ty) {
48600 this.toolbars[i] = this.buildToolbar(ty[i],i);
48602 this.tb = this.toolbars.BODY;
48604 this.buildFooter();
48605 this.footer.show();
48606 editor.on('hide', function( ) { this.footer.hide() }, this);
48607 editor.on('show', function( ) { this.footer.show() }, this);
48610 this.rendered = true;
48612 // the all the btns;
48613 editor.on('editorevent', this.updateToolbar, this);
48614 // other toolbars need to implement this..
48615 //editor.on('editmodechange', this.updateToolbar, this);
48621 * Protected method that will not generally be called directly. It triggers
48622 * a toolbar update by reading the markup state of the current selection in the editor.
48624 * Note you can force an update by calling on('editorevent', scope, false)
48626 updateToolbar: function(editor ,ev, sel){
48629 // capture mouse up - this is handy for selecting images..
48630 // perhaps should go somewhere else...
48631 if(!this.editorcore.activated){
48632 this.editor.onFirstFocus();
48638 // http://developer.yahoo.com/yui/docs/simple-editor.js.html
48639 // selectNode - might want to handle IE?
48644 (ev.type == 'mouseup' || ev.type == 'click' ) &&
48645 ev.target && ev.target.tagName == 'IMG') {
48646 // they have click on an image...
48647 // let's see if we can change the selection...
48650 var nodeRange = sel.ownerDocument.createRange();
48652 nodeRange.selectNode(sel);
48654 nodeRange.selectNodeContents(sel);
48656 //nodeRange.collapse(true);
48657 var s = this.editorcore.win.getSelection();
48658 s.removeAllRanges();
48659 s.addRange(nodeRange);
48663 //var updateFooter = sel ? false : true;
48666 var ans = this.editorcore.getAllAncestors();
48669 var ty = Roo.form.HtmlEditor.ToolbarContext.types;
48672 sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editorcore.doc.body;
48673 sel = sel ? sel : this.editorcore.doc.body;
48674 sel = sel.tagName.length ? sel : this.editorcore.doc.body;
48678 var tn = sel.tagName.toUpperCase();
48679 var lastSel = this.tb.selectedNode;
48680 this.tb.selectedNode = sel;
48681 var left_label = tn;
48683 // ok see if we are editing a block?
48685 var db = Roo.get(sel).findParent('[data-block]');
48688 block = Roo.htmleditor.Block.factory(db);
48690 tn = 'BLOCK.' + db.getAttribute('data-block');
48691 this.tb.selectedNode = db;
48692 if (typeof(this.toolbars[tn]) == 'undefined') {
48693 this.toolbars[tn] = this.buildToolbar( block.context,tn ,block.friendly_name);
48695 left_label = block.friendly_name;
48703 if (this.tb.name == tn && lastSel == this.tb.selectedNode && ev !== false) {
48704 return; // no change?
48710 ///console.log("show: " + tn);
48711 this.tb = typeof(this.toolbars[tn]) != 'undefined' ? this.toolbars[tn] : this.toolbars['*'];
48715 this.tb.items.first().el.innerHTML = left_label + ': ';
48718 // update attributes
48721 this.tb.fields.each(function(e) {
48722 e.setValue(block[e.attrname]);
48726 } else if (this.tb.fields) {
48727 this.tb.fields.each(function(e) {
48729 e.setValue(sel.style[e.stylename]);
48732 e.setValue(sel.getAttribute(e.attrname));
48735 this.updateToolbarStyles(sel);
48739 Roo.menu.MenuMgr.hideAll();
48744 // update the footer
48746 this.updateFooter(ans);
48750 updateToolbarStyles : function(sel)
48752 var hasStyles = false;
48753 for(var i in this.styles) {
48760 var st = this.tb.fields.item(0);
48762 st.store.removeAll();
48763 var cn = sel.className.split(/\s+/);
48766 if (this.styles['*']) {
48768 Roo.each(this.styles['*'], function(v) {
48769 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
48772 if (this.styles[tn]) {
48773 Roo.each(this.styles[tn], function(v) {
48774 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
48778 st.store.loadData(avs);
48785 updateFooter : function(ans)
48788 if (ans === false) {
48789 this.footDisp.dom.innerHTML = '';
48793 this.footerEls = ans.reverse();
48794 Roo.each(this.footerEls, function(a,i) {
48795 if (!a) { return; }
48796 html += html.length ? ' > ' : '';
48798 html += '<span class="x-ed-loc-' + i + '">' + a.tagName + '</span>';
48803 var sz = this.footDisp.up('td').getSize();
48804 this.footDisp.dom.style.width = (sz.width -10) + 'px';
48805 this.footDisp.dom.style.marginLeft = '5px';
48807 this.footDisp.dom.style.overflow = 'hidden';
48809 this.footDisp.dom.innerHTML = html;
48816 onDestroy : function(){
48819 this.tb.items.each(function(item){
48821 item.menu.removeAll();
48823 item.menu.el.destroy();
48831 onFirstFocus: function() {
48832 // need to do this for all the toolbars..
48833 this.tb.items.each(function(item){
48837 buildToolbar: function(tlist, nm, friendly_name)
48839 var editor = this.editor;
48840 var editorcore = this.editorcore;
48841 // create a new element.
48842 var wdiv = editor.wrap.createChild({
48844 }, editor.wrap.dom.firstChild.nextSibling, true);
48847 var tb = new Roo.Toolbar(wdiv);
48850 tb.add((typeof(friendly_name) == 'undefined' ? nm : friendly_name) + ": ");
48852 var styles = Array.from(this.styles);
48856 if (styles && styles.length) {
48858 // this needs a multi-select checkbox...
48859 tb.addField( new Roo.form.ComboBox({
48860 store: new Roo.data.SimpleStore({
48862 fields: ['val', 'selected'],
48865 name : '-roo-edit-className',
48866 attrname : 'className',
48867 displayField: 'val',
48871 triggerAction: 'all',
48872 emptyText:'Select Style',
48873 selectOnFocus:true,
48876 'select': function(c, r, i) {
48877 // initial support only for on class per el..
48878 tb.selectedNode.className = r ? r.get('val') : '';
48879 editorcore.syncValue();
48886 var tbc = Roo.form.HtmlEditor.ToolbarContext;
48889 for (var i in tlist) {
48891 var item = tlist[i];
48892 tb.add(item.title + ": ");
48895 //optname == used so you can configure the options available..
48896 var opts = item.opts ? item.opts : false;
48897 if (item.optname) { // use the b
48898 opts = Roo.form.HtmlEditor.ToolbarContext.options[item.optname];
48903 // opts == pulldown..
48904 tb.addField( new Roo.form.ComboBox({
48905 store: typeof(tbc.stores[i]) != 'undefined' ? Roo.factory(tbc.stores[i],Roo.data) : new Roo.data.SimpleStore({
48907 fields: ['val', 'display'],
48910 name : '-roo-edit-' + i,
48913 stylename : item.style ? item.style : false,
48915 displayField: item.displayField ? item.displayField : 'val',
48916 valueField : 'val',
48918 mode: typeof(tbc.stores[i]) != 'undefined' ? 'remote' : 'local',
48920 triggerAction: 'all',
48921 emptyText:'Select',
48922 selectOnFocus:true,
48923 width: item.width ? item.width : 130,
48925 'select': function(c, r, i) {
48926 if (tb.selectedNode.hasAttribute('data-block')) {
48927 var b = Roo.htmleditor.Block.factory(tb.selectedNode);
48928 b[c.attrname] = r.get('val');
48929 b.updateElement(tb.selectedNode);
48930 editorcore.syncValue();
48935 tb.selectedNode.style[c.stylename] = r.get('val');
48936 editorcore.syncValue();
48940 tb.selectedNode.removeAttribute(c.attrname);
48941 editorcore.syncValue();
48944 tb.selectedNode.setAttribute(c.attrname, r.get('val'));
48945 editorcore.syncValue();
48954 tb.addField( new Roo.form.TextField({
48957 //allowBlank:false,
48963 tb.addField( new Roo.form.TextField({
48964 name: '-roo-edit-' + i,
48971 'change' : function(f, nv, ov) {
48973 if (tb.selectedNode.hasAttribute('data-block')) {
48974 var b = Roo.htmleditor.Block.factory(tb.selectedNode);
48975 b[f.attrname] = nv;
48976 b.updateElement(tb.selectedNode);
48977 editorcore.syncValue();
48981 tb.selectedNode.setAttribute(f.attrname, nv);
48982 editorcore.syncValue();
48995 text: 'Stylesheets',
48998 click : function ()
49000 _this.editor.fireEvent('stylesheetsclick', _this.editor);
49008 text: 'Remove', // remove the tag, and puts the children outside...
49011 click : function ()
49014 // undo does not work.
49015 var sn = tb.selectedNode;
49016 var stn = sn.childNodes[0] || sn.nextSibling || sn.previousSibling || sn.parentNode;
49017 if (sn.hasAttribute('data-block')) {
49018 stn = sn.nextSibling || sn.previousSibling || sn.parentNode;
49019 sn.parentNode.removeChild(sn);
49022 // remove and keep parents.
49023 a = new Roo.htmleditor.FilterKeepChildren({tag : false});
49028 var range = editorcore.createRange();
49030 range.setStart(stn,0);
49031 range.setEnd(en,0); //????
49032 var selection = editorcore.getSelection();
49033 selection.removeAllRanges();
49034 selection.addRange(range);
49037 //_this.updateToolbar(null, null, pn);
49038 _this.updateToolbar(null, null, null);
49039 _this.updateFooter(false);
49050 tb.el.on('click', function(e){
49051 e.preventDefault(); // what does this do?
49053 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
49056 // dont need to disable them... as they will get hidden
49061 buildFooter : function()
49064 var fel = this.editor.wrap.createChild();
49065 this.footer = new Roo.Toolbar(fel);
49066 // toolbar has scrolly on left / right?
49067 var footDisp= new Roo.Toolbar.Fill();
49073 handler : function() {
49074 _t.footDisp.scrollTo('left',0,true)
49078 this.footer.add( footDisp );
49083 handler : function() {
49085 _t.footDisp.select('span').last().scrollIntoView(_t.footDisp,true);
49089 var fel = Roo.get(footDisp.el);
49090 fel.addClass('x-editor-context');
49091 this.footDispWrap = fel;
49092 this.footDispWrap.overflow = 'hidden';
49094 this.footDisp = fel.createChild();
49095 this.footDispWrap.on('click', this.onContextClick, this)
49099 onContextClick : function (ev,dom)
49101 ev.preventDefault();
49102 var cn = dom.className;
49104 if (!cn.match(/x-ed-loc-/)) {
49107 var n = cn.split('-').pop();
49108 var ans = this.footerEls;
49112 var range = this.editorcore.createRange();
49114 range.selectNodeContents(sel);
49115 //range.selectNode(sel);
49118 var selection = this.editorcore.getSelection();
49119 selection.removeAllRanges();
49120 selection.addRange(range);
49124 this.updateToolbar(null, null, sel);
49141 * Ext JS Library 1.1.1
49142 * Copyright(c) 2006-2007, Ext JS, LLC.
49144 * Originally Released Under LGPL - original licence link has changed is not relivant.
49147 * <script type="text/javascript">
49151 * @class Roo.form.BasicForm
49152 * @extends Roo.util.Observable
49153 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
49155 * @param {String/HTMLElement/Roo.Element} el The form element or its id
49156 * @param {Object} config Configuration options
49158 Roo.form.BasicForm = function(el, config){
49159 this.allItems = [];
49160 this.childForms = [];
49161 Roo.apply(this, config);
49163 * The Roo.form.Field items in this form.
49164 * @type MixedCollection
49168 this.items = new Roo.util.MixedCollection(false, function(o){
49169 return o.id || (o.id = Roo.id());
49173 * @event beforeaction
49174 * Fires before any action is performed. Return false to cancel the action.
49175 * @param {Form} this
49176 * @param {Action} action The action to be performed
49178 beforeaction: true,
49180 * @event actionfailed
49181 * Fires when an action fails.
49182 * @param {Form} this
49183 * @param {Action} action The action that failed
49185 actionfailed : true,
49187 * @event actioncomplete
49188 * Fires when an action is completed.
49189 * @param {Form} this
49190 * @param {Action} action The action that completed
49192 actioncomplete : true
49197 Roo.form.BasicForm.superclass.constructor.call(this);
49199 Roo.form.BasicForm.popover.apply();
49202 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
49204 * @cfg {String} method
49205 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
49208 * @cfg {DataReader} reader
49209 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
49210 * This is optional as there is built-in support for processing JSON.
49213 * @cfg {DataReader} errorReader
49214 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
49215 * This is completely optional as there is built-in support for processing JSON.
49218 * @cfg {String} url
49219 * The URL to use for form actions if one isn't supplied in the action options.
49222 * @cfg {Boolean} fileUpload
49223 * Set to true if this form is a file upload.
49227 * @cfg {Object} baseParams
49228 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
49233 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
49238 activeAction : null,
49241 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
49242 * or setValues() data instead of when the form was first created.
49244 trackResetOnLoad : false,
49248 * childForms - used for multi-tab forms
49251 childForms : false,
49254 * allItems - full list of fields.
49260 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
49261 * element by passing it or its id or mask the form itself by passing in true.
49264 waitMsgTarget : false,
49269 disableMask : false,
49272 * @cfg {Boolean} errorMask (true|false) default false
49277 * @cfg {Number} maskOffset Default 100
49282 initEl : function(el){
49283 this.el = Roo.get(el);
49284 this.id = this.el.id || Roo.id();
49285 this.el.on('submit', this.onSubmit, this);
49286 this.el.addClass('x-form');
49290 onSubmit : function(e){
49295 * Returns true if client-side validation on the form is successful.
49298 isValid : function(){
49300 var target = false;
49301 this.items.each(function(f){
49308 if(!target && f.el.isVisible(true)){
49313 if(this.errorMask && !valid){
49314 Roo.form.BasicForm.popover.mask(this, target);
49320 * Returns array of invalid form fields.
49324 invalidFields : function()
49327 this.items.each(function(f){
49340 * DEPRICATED Returns true if any fields in this form have changed since their original load.
49343 isDirty : function(){
49345 this.items.each(function(f){
49355 * Returns true if any fields in this form have changed since their original load. (New version)
49359 hasChanged : function()
49362 this.items.each(function(f){
49363 if(f.hasChanged()){
49372 * Resets all hasChanged to 'false' -
49373 * The old 'isDirty' used 'original value..' however this breaks reset() and a few other things.
49374 * So hasChanged storage is only to be used for this purpose
49377 resetHasChanged : function()
49379 this.items.each(function(f){
49380 f.resetHasChanged();
49387 * Performs a predefined action (submit or load) or custom actions you define on this form.
49388 * @param {String} actionName The name of the action type
49389 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
49390 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
49391 * accept other config options):
49393 Property Type Description
49394 ---------------- --------------- ----------------------------------------------------------------------------------
49395 url String The url for the action (defaults to the form's url)
49396 method String The form method to use (defaults to the form's method, or POST if not defined)
49397 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
49398 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
49399 validate the form on the client (defaults to false)
49401 * @return {BasicForm} this
49403 doAction : function(action, options){
49404 if(typeof action == 'string'){
49405 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
49407 if(this.fireEvent('beforeaction', this, action) !== false){
49408 this.beforeAction(action);
49409 action.run.defer(100, action);
49415 * Shortcut to do a submit action.
49416 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
49417 * @return {BasicForm} this
49419 submit : function(options){
49420 this.doAction('submit', options);
49425 * Shortcut to do a load action.
49426 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
49427 * @return {BasicForm} this
49429 load : function(options){
49430 this.doAction('load', options);
49435 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
49436 * @param {Record} record The record to edit
49437 * @return {BasicForm} this
49439 updateRecord : function(record){
49440 record.beginEdit();
49441 var fs = record.fields;
49442 fs.each(function(f){
49443 var field = this.findField(f.name);
49445 record.set(f.name, field.getValue());
49453 * Loads an Roo.data.Record into this form.
49454 * @param {Record} record The record to load
49455 * @return {BasicForm} this
49457 loadRecord : function(record){
49458 this.setValues(record.data);
49463 beforeAction : function(action){
49464 var o = action.options;
49466 if(!this.disableMask) {
49467 if(this.waitMsgTarget === true){
49468 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
49469 }else if(this.waitMsgTarget){
49470 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
49471 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
49473 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
49481 afterAction : function(action, success){
49482 this.activeAction = null;
49483 var o = action.options;
49485 if(!this.disableMask) {
49486 if(this.waitMsgTarget === true){
49488 }else if(this.waitMsgTarget){
49489 this.waitMsgTarget.unmask();
49491 Roo.MessageBox.updateProgress(1);
49492 Roo.MessageBox.hide();
49500 Roo.callback(o.success, o.scope, [this, action]);
49501 this.fireEvent('actioncomplete', this, action);
49505 // failure condition..
49506 // we have a scenario where updates need confirming.
49507 // eg. if a locking scenario exists..
49508 // we look for { errors : { needs_confirm : true }} in the response.
49510 (typeof(action.result) != 'undefined') &&
49511 (typeof(action.result.errors) != 'undefined') &&
49512 (typeof(action.result.errors.needs_confirm) != 'undefined')
49515 Roo.MessageBox.confirm(
49516 "Change requires confirmation",
49517 action.result.errorMsg,
49522 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
49532 Roo.callback(o.failure, o.scope, [this, action]);
49533 // show an error message if no failed handler is set..
49534 if (!this.hasListener('actionfailed')) {
49535 Roo.MessageBox.alert("Error",
49536 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
49537 action.result.errorMsg :
49538 "Saving Failed, please check your entries or try again"
49542 this.fireEvent('actionfailed', this, action);
49548 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
49549 * @param {String} id The value to search for
49552 findField : function(id){
49553 var field = this.items.get(id);
49555 this.items.each(function(f){
49556 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
49562 return field || null;
49566 * Add a secondary form to this one,
49567 * Used to provide tabbed forms. One form is primary, with hidden values
49568 * which mirror the elements from the other forms.
49570 * @param {Roo.form.Form} form to add.
49573 addForm : function(form)
49576 if (this.childForms.indexOf(form) > -1) {
49580 this.childForms.push(form);
49582 Roo.each(form.allItems, function (fe) {
49584 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
49585 if (this.findField(n)) { // already added..
49588 var add = new Roo.form.Hidden({
49591 add.render(this.el);
49598 * Mark fields in this form invalid in bulk.
49599 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
49600 * @return {BasicForm} this
49602 markInvalid : function(errors){
49603 if(errors instanceof Array){
49604 for(var i = 0, len = errors.length; i < len; i++){
49605 var fieldError = errors[i];
49606 var f = this.findField(fieldError.id);
49608 f.markInvalid(fieldError.msg);
49614 if(typeof errors[id] != 'function' && (field = this.findField(id))){
49615 field.markInvalid(errors[id]);
49619 Roo.each(this.childForms || [], function (f) {
49620 f.markInvalid(errors);
49627 * Set values for fields in this form in bulk.
49628 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
49629 * @return {BasicForm} this
49631 setValues : function(values){
49632 if(values instanceof Array){ // array of objects
49633 for(var i = 0, len = values.length; i < len; i++){
49635 var f = this.findField(v.id);
49637 f.setValue(v.value);
49638 if(this.trackResetOnLoad){
49639 f.originalValue = f.getValue();
49643 }else{ // object hash
49646 if(typeof values[id] != 'function' && (field = this.findField(id))){
49648 if (field.setFromData &&
49649 field.valueField &&
49650 field.displayField &&
49651 // combos' with local stores can
49652 // be queried via setValue()
49653 // to set their value..
49654 (field.store && !field.store.isLocal)
49658 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
49659 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
49660 field.setFromData(sd);
49663 field.setValue(values[id]);
49667 if(this.trackResetOnLoad){
49668 field.originalValue = field.getValue();
49673 this.resetHasChanged();
49676 Roo.each(this.childForms || [], function (f) {
49677 f.setValues(values);
49678 f.resetHasChanged();
49685 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
49686 * they are returned as an array.
49687 * @param {Boolean} asString
49690 getValues : function(asString){
49691 if (this.childForms) {
49692 // copy values from the child forms
49693 Roo.each(this.childForms, function (f) {
49694 this.setValues(f.getValues());
49699 if (typeof(FormData) != 'undefined' && asString !== true) {
49700 // this relies on a 'recent' version of chrome apparently...
49702 var fd = (new FormData(this.el.dom)).entries();
49704 var ent = fd.next();
49705 while (!ent.done) {
49706 ret[ent.value[0]] = ent.value[1]; // not sure how this will handle duplicates..
49717 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
49718 if(asString === true){
49721 return Roo.urlDecode(fs);
49725 * Returns the fields in this form as an object with key/value pairs.
49726 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
49729 getFieldValues : function(with_hidden)
49731 if (this.childForms) {
49732 // copy values from the child forms
49733 // should this call getFieldValues - probably not as we do not currently copy
49734 // hidden fields when we generate..
49735 Roo.each(this.childForms, function (f) {
49736 this.setValues(f.getValues());
49741 this.items.each(function(f){
49742 if (!f.getName()) {
49745 var v = f.getValue();
49746 if (f.inputType =='radio') {
49747 if (typeof(ret[f.getName()]) == 'undefined') {
49748 ret[f.getName()] = ''; // empty..
49751 if (!f.el.dom.checked) {
49755 v = f.el.dom.value;
49759 // not sure if this supported any more..
49760 if ((typeof(v) == 'object') && f.getRawValue) {
49761 v = f.getRawValue() ; // dates..
49763 // combo boxes where name != hiddenName...
49764 if (f.name != f.getName()) {
49765 ret[f.name] = f.getRawValue();
49767 ret[f.getName()] = v;
49774 * Clears all invalid messages in this form.
49775 * @return {BasicForm} this
49777 clearInvalid : function(){
49778 this.items.each(function(f){
49782 Roo.each(this.childForms || [], function (f) {
49791 * Resets this form.
49792 * @return {BasicForm} this
49794 reset : function(){
49795 this.items.each(function(f){
49799 Roo.each(this.childForms || [], function (f) {
49802 this.resetHasChanged();
49808 * Add Roo.form components to this form.
49809 * @param {Field} field1
49810 * @param {Field} field2 (optional)
49811 * @param {Field} etc (optional)
49812 * @return {BasicForm} this
49815 this.items.addAll(Array.prototype.slice.call(arguments, 0));
49821 * Removes a field from the items collection (does NOT remove its markup).
49822 * @param {Field} field
49823 * @return {BasicForm} this
49825 remove : function(field){
49826 this.items.remove(field);
49831 * Looks at the fields in this form, checks them for an id attribute,
49832 * and calls applyTo on the existing dom element with that id.
49833 * @return {BasicForm} this
49835 render : function(){
49836 this.items.each(function(f){
49837 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
49845 * Calls {@link Ext#apply} for all fields in this form with the passed object.
49846 * @param {Object} values
49847 * @return {BasicForm} this
49849 applyToFields : function(o){
49850 this.items.each(function(f){
49857 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
49858 * @param {Object} values
49859 * @return {BasicForm} this
49861 applyIfToFields : function(o){
49862 this.items.each(function(f){
49870 Roo.BasicForm = Roo.form.BasicForm;
49872 Roo.apply(Roo.form.BasicForm, {
49886 intervalID : false,
49892 if(this.isApplied){
49897 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
49898 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
49899 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
49900 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
49903 this.maskEl.top.enableDisplayMode("block");
49904 this.maskEl.left.enableDisplayMode("block");
49905 this.maskEl.bottom.enableDisplayMode("block");
49906 this.maskEl.right.enableDisplayMode("block");
49908 Roo.get(document.body).on('click', function(){
49912 Roo.get(document.body).on('touchstart', function(){
49916 this.isApplied = true
49919 mask : function(form, target)
49923 this.target = target;
49925 if(!this.form.errorMask || !target.el){
49929 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.x-layout-active-content', 100, true) || Roo.get(document.body);
49931 var ot = this.target.el.calcOffsetsTo(scrollable);
49933 var scrollTo = ot[1] - this.form.maskOffset;
49935 scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
49937 scrollable.scrollTo('top', scrollTo);
49939 var el = this.target.wrap || this.target.el;
49941 var box = el.getBox();
49943 this.maskEl.top.setStyle('position', 'absolute');
49944 this.maskEl.top.setStyle('z-index', 10000);
49945 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
49946 this.maskEl.top.setLeft(0);
49947 this.maskEl.top.setTop(0);
49948 this.maskEl.top.show();
49950 this.maskEl.left.setStyle('position', 'absolute');
49951 this.maskEl.left.setStyle('z-index', 10000);
49952 this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
49953 this.maskEl.left.setLeft(0);
49954 this.maskEl.left.setTop(box.y - this.padding);
49955 this.maskEl.left.show();
49957 this.maskEl.bottom.setStyle('position', 'absolute');
49958 this.maskEl.bottom.setStyle('z-index', 10000);
49959 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
49960 this.maskEl.bottom.setLeft(0);
49961 this.maskEl.bottom.setTop(box.bottom + this.padding);
49962 this.maskEl.bottom.show();
49964 this.maskEl.right.setStyle('position', 'absolute');
49965 this.maskEl.right.setStyle('z-index', 10000);
49966 this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
49967 this.maskEl.right.setLeft(box.right + this.padding);
49968 this.maskEl.right.setTop(box.y - this.padding);
49969 this.maskEl.right.show();
49971 this.intervalID = window.setInterval(function() {
49972 Roo.form.BasicForm.popover.unmask();
49975 window.onwheel = function(){ return false;};
49977 (function(){ this.isMasked = true; }).defer(500, this);
49981 unmask : function()
49983 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
49987 this.maskEl.top.setStyle('position', 'absolute');
49988 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
49989 this.maskEl.top.hide();
49991 this.maskEl.left.setStyle('position', 'absolute');
49992 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
49993 this.maskEl.left.hide();
49995 this.maskEl.bottom.setStyle('position', 'absolute');
49996 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
49997 this.maskEl.bottom.hide();
49999 this.maskEl.right.setStyle('position', 'absolute');
50000 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
50001 this.maskEl.right.hide();
50003 window.onwheel = function(){ return true;};
50005 if(this.intervalID){
50006 window.clearInterval(this.intervalID);
50007 this.intervalID = false;
50010 this.isMasked = false;
50018 * Ext JS Library 1.1.1
50019 * Copyright(c) 2006-2007, Ext JS, LLC.
50021 * Originally Released Under LGPL - original licence link has changed is not relivant.
50024 * <script type="text/javascript">
50028 * @class Roo.form.Form
50029 * @extends Roo.form.BasicForm
50030 * @children Roo.form.Column Roo.form.FieldSet Roo.form.Row Roo.form.Field Roo.Button Roo.form.TextItem
50031 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
50033 * @param {Object} config Configuration options
50035 Roo.form.Form = function(config){
50037 if (config.items) {
50038 xitems = config.items;
50039 delete config.items;
50043 Roo.form.Form.superclass.constructor.call(this, null, config);
50044 this.url = this.url || this.action;
50046 this.root = new Roo.form.Layout(Roo.applyIf({
50050 this.active = this.root;
50052 * Array of all the buttons that have been added to this form via {@link addButton}
50056 this.allItems = [];
50059 * @event clientvalidation
50060 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
50061 * @param {Form} this
50062 * @param {Boolean} valid true if the form has passed client-side validation
50064 clientvalidation: true,
50067 * Fires when the form is rendered
50068 * @param {Roo.form.Form} form
50073 if (this.progressUrl) {
50074 // push a hidden field onto the list of fields..
50078 name : 'UPLOAD_IDENTIFIER'
50083 Roo.each(xitems, this.addxtype, this);
50087 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
50089 * @cfg {Roo.Button} buttons[] buttons at bottom of form
50093 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
50096 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
50099 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
50101 buttonAlign:'center',
50104 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
50109 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
50110 * This property cascades to child containers if not set.
50115 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
50116 * fires a looping event with that state. This is required to bind buttons to the valid
50117 * state using the config value formBind:true on the button.
50119 monitorValid : false,
50122 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
50127 * @cfg {String} progressUrl - Url to return progress data
50130 progressUrl : false,
50132 * @cfg {boolean|FormData} formData - true to use new 'FormData' post, or set to a new FormData({dom form}) Object, if
50133 * sending a formdata with extra parameters - eg uploaded elements.
50139 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
50140 * fields are added and the column is closed. If no fields are passed the column remains open
50141 * until end() is called.
50142 * @param {Object} config The config to pass to the column
50143 * @param {Field} field1 (optional)
50144 * @param {Field} field2 (optional)
50145 * @param {Field} etc (optional)
50146 * @return Column The column container object
50148 column : function(c){
50149 var col = new Roo.form.Column(c);
50151 if(arguments.length > 1){ // duplicate code required because of Opera
50152 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
50159 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
50160 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
50161 * until end() is called.
50162 * @param {Object} config The config to pass to the fieldset
50163 * @param {Field} field1 (optional)
50164 * @param {Field} field2 (optional)
50165 * @param {Field} etc (optional)
50166 * @return FieldSet The fieldset container object
50168 fieldset : function(c){
50169 var fs = new Roo.form.FieldSet(c);
50171 if(arguments.length > 1){ // duplicate code required because of Opera
50172 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
50179 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
50180 * fields are added and the container is closed. If no fields are passed the container remains open
50181 * until end() is called.
50182 * @param {Object} config The config to pass to the Layout
50183 * @param {Field} field1 (optional)
50184 * @param {Field} field2 (optional)
50185 * @param {Field} etc (optional)
50186 * @return Layout The container object
50188 container : function(c){
50189 var l = new Roo.form.Layout(c);
50191 if(arguments.length > 1){ // duplicate code required because of Opera
50192 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
50199 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
50200 * @param {Object} container A Roo.form.Layout or subclass of Layout
50201 * @return {Form} this
50203 start : function(c){
50204 // cascade label info
50205 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
50206 this.active.stack.push(c);
50207 c.ownerCt = this.active;
50213 * Closes the current open container
50214 * @return {Form} this
50217 if(this.active == this.root){
50220 this.active = this.active.ownerCt;
50225 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
50226 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
50227 * as the label of the field.
50228 * @param {Field} field1
50229 * @param {Field} field2 (optional)
50230 * @param {Field} etc. (optional)
50231 * @return {Form} this
50234 this.active.stack.push.apply(this.active.stack, arguments);
50235 this.allItems.push.apply(this.allItems,arguments);
50237 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
50238 if(a[i].isFormField){
50243 Roo.form.Form.superclass.add.apply(this, r);
50253 * Find any element that has been added to a form, using it's ID or name
50254 * This can include framesets, columns etc. along with regular fields..
50255 * @param {String} id - id or name to find.
50257 * @return {Element} e - or false if nothing found.
50259 findbyId : function(id)
50265 Roo.each(this.allItems, function(f){
50266 if (f.id == id || f.name == id ){
50277 * Render this form into the passed container. This should only be called once!
50278 * @param {String/HTMLElement/Element} container The element this component should be rendered into
50279 * @return {Form} this
50281 render : function(ct)
50287 var o = this.autoCreate || {
50289 method : this.method || 'POST',
50290 id : this.id || Roo.id()
50292 this.initEl(ct.createChild(o));
50294 this.root.render(this.el);
50298 this.items.each(function(f){
50299 f.render('x-form-el-'+f.id);
50302 if(this.buttons.length > 0){
50303 // tables are required to maintain order and for correct IE layout
50304 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
50305 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
50306 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
50308 var tr = tb.getElementsByTagName('tr')[0];
50309 for(var i = 0, len = this.buttons.length; i < len; i++) {
50310 var b = this.buttons[i];
50311 var td = document.createElement('td');
50312 td.className = 'x-form-btn-td';
50313 b.render(tr.appendChild(td));
50316 if(this.monitorValid){ // initialize after render
50317 this.startMonitoring();
50319 this.fireEvent('rendered', this);
50324 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
50325 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
50326 * object or a valid Roo.DomHelper element config
50327 * @param {Function} handler The function called when the button is clicked
50328 * @param {Object} scope (optional) The scope of the handler function
50329 * @return {Roo.Button}
50331 addButton : function(config, handler, scope){
50335 minWidth: this.minButtonWidth,
50338 if(typeof config == "string"){
50341 Roo.apply(bc, config);
50343 var btn = new Roo.Button(null, bc);
50344 this.buttons.push(btn);
50349 * Adds a series of form elements (using the xtype property as the factory method.
50350 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
50351 * @param {Object} config
50354 addxtype : function()
50356 var ar = Array.prototype.slice.call(arguments, 0);
50358 for(var i = 0; i < ar.length; i++) {
50360 continue; // skip -- if this happends something invalid got sent, we
50361 // should ignore it, as basically that interface element will not show up
50362 // and that should be pretty obvious!!
50365 if (Roo.form[ar[i].xtype]) {
50367 var fe = Roo.factory(ar[i], Roo.form);
50373 fe.store.form = this;
50378 this.allItems.push(fe);
50379 if (fe.items && fe.addxtype) {
50380 fe.addxtype.apply(fe, fe.items);
50390 // console.log('adding ' + ar[i].xtype);
50392 if (ar[i].xtype == 'Button') {
50393 //console.log('adding button');
50394 //console.log(ar[i]);
50395 this.addButton(ar[i]);
50396 this.allItems.push(fe);
50400 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
50401 alert('end is not supported on xtype any more, use items');
50403 // //console.log('adding end');
50411 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
50412 * option "monitorValid"
50414 startMonitoring : function(){
50417 Roo.TaskMgr.start({
50418 run : this.bindHandler,
50419 interval : this.monitorPoll || 200,
50426 * Stops monitoring of the valid state of this form
50428 stopMonitoring : function(){
50429 this.bound = false;
50433 bindHandler : function(){
50435 return false; // stops binding
50438 this.items.each(function(f){
50439 if(!f.isValid(true)){
50444 for(var i = 0, len = this.buttons.length; i < len; i++){
50445 var btn = this.buttons[i];
50446 if(btn.formBind === true && btn.disabled === valid){
50447 btn.setDisabled(!valid);
50450 this.fireEvent('clientvalidation', this, valid);
50464 Roo.Form = Roo.form.Form;
50467 * Ext JS Library 1.1.1
50468 * Copyright(c) 2006-2007, Ext JS, LLC.
50470 * Originally Released Under LGPL - original licence link has changed is not relivant.
50473 * <script type="text/javascript">
50476 // as we use this in bootstrap.
50477 Roo.namespace('Roo.form');
50479 * @class Roo.form.Action
50480 * Internal Class used to handle form actions
50482 * @param {Roo.form.BasicForm} el The form element or its id
50483 * @param {Object} config Configuration options
50488 // define the action interface
50489 Roo.form.Action = function(form, options){
50491 this.options = options || {};
50494 * Client Validation Failed
50497 Roo.form.Action.CLIENT_INVALID = 'client';
50499 * Server Validation Failed
50502 Roo.form.Action.SERVER_INVALID = 'server';
50504 * Connect to Server Failed
50507 Roo.form.Action.CONNECT_FAILURE = 'connect';
50509 * Reading Data from Server Failed
50512 Roo.form.Action.LOAD_FAILURE = 'load';
50514 Roo.form.Action.prototype = {
50516 failureType : undefined,
50517 response : undefined,
50518 result : undefined,
50520 // interface method
50521 run : function(options){
50525 // interface method
50526 success : function(response){
50530 // interface method
50531 handleResponse : function(response){
50535 // default connection failure
50536 failure : function(response){
50538 this.response = response;
50539 this.failureType = Roo.form.Action.CONNECT_FAILURE;
50540 this.form.afterAction(this, false);
50543 processResponse : function(response){
50544 this.response = response;
50545 if(!response.responseText){
50548 this.result = this.handleResponse(response);
50549 return this.result;
50552 // utility functions used internally
50553 getUrl : function(appendParams){
50554 var url = this.options.url || this.form.url || this.form.el.dom.action;
50556 var p = this.getParams();
50558 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
50564 getMethod : function(){
50565 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
50568 getParams : function(){
50569 var bp = this.form.baseParams;
50570 var p = this.options.params;
50572 if(typeof p == "object"){
50573 p = Roo.urlEncode(Roo.applyIf(p, bp));
50574 }else if(typeof p == 'string' && bp){
50575 p += '&' + Roo.urlEncode(bp);
50578 p = Roo.urlEncode(bp);
50583 createCallback : function(){
50585 success: this.success,
50586 failure: this.failure,
50588 timeout: (this.form.timeout*1000),
50589 upload: this.form.fileUpload ? this.success : undefined
50594 Roo.form.Action.Submit = function(form, options){
50595 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
50598 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
50601 haveProgress : false,
50602 uploadComplete : false,
50604 // uploadProgress indicator.
50605 uploadProgress : function()
50607 if (!this.form.progressUrl) {
50611 if (!this.haveProgress) {
50612 Roo.MessageBox.progress("Uploading", "Uploading");
50614 if (this.uploadComplete) {
50615 Roo.MessageBox.hide();
50619 this.haveProgress = true;
50621 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
50623 var c = new Roo.data.Connection();
50625 url : this.form.progressUrl,
50630 success : function(req){
50631 //console.log(data);
50635 rdata = Roo.decode(req.responseText)
50637 Roo.log("Invalid data from server..");
50641 if (!rdata || !rdata.success) {
50643 Roo.MessageBox.alert(Roo.encode(rdata));
50646 var data = rdata.data;
50648 if (this.uploadComplete) {
50649 Roo.MessageBox.hide();
50654 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
50655 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
50658 this.uploadProgress.defer(2000,this);
50661 failure: function(data) {
50662 Roo.log('progress url failed ');
50673 // run get Values on the form, so it syncs any secondary forms.
50674 this.form.getValues();
50676 var o = this.options;
50677 var method = this.getMethod();
50678 var isPost = method == 'POST';
50679 if(o.clientValidation === false || this.form.isValid()){
50681 if (this.form.progressUrl) {
50682 this.form.findField('UPLOAD_IDENTIFIER').setValue(
50683 (new Date() * 1) + '' + Math.random());
50688 Roo.Ajax.request(Roo.apply(this.createCallback(), {
50689 form:this.form.el.dom,
50690 url:this.getUrl(!isPost),
50692 params:isPost ? this.getParams() : null,
50693 isUpload: this.form.fileUpload,
50694 formData : this.form.formData
50697 this.uploadProgress();
50699 }else if (o.clientValidation !== false){ // client validation failed
50700 this.failureType = Roo.form.Action.CLIENT_INVALID;
50701 this.form.afterAction(this, false);
50705 success : function(response)
50707 this.uploadComplete= true;
50708 if (this.haveProgress) {
50709 Roo.MessageBox.hide();
50713 var result = this.processResponse(response);
50714 if(result === true || result.success){
50715 this.form.afterAction(this, true);
50719 this.form.markInvalid(result.errors);
50720 this.failureType = Roo.form.Action.SERVER_INVALID;
50722 this.form.afterAction(this, false);
50724 failure : function(response)
50726 this.uploadComplete= true;
50727 if (this.haveProgress) {
50728 Roo.MessageBox.hide();
50731 this.response = response;
50732 this.failureType = Roo.form.Action.CONNECT_FAILURE;
50733 this.form.afterAction(this, false);
50736 handleResponse : function(response){
50737 if(this.form.errorReader){
50738 var rs = this.form.errorReader.read(response);
50741 for(var i = 0, len = rs.records.length; i < len; i++) {
50742 var r = rs.records[i];
50743 errors[i] = r.data;
50746 if(errors.length < 1){
50750 success : rs.success,
50756 ret = Roo.decode(response.responseText);
50760 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
50770 Roo.form.Action.Load = function(form, options){
50771 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
50772 this.reader = this.form.reader;
50775 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
50780 Roo.Ajax.request(Roo.apply(
50781 this.createCallback(), {
50782 method:this.getMethod(),
50783 url:this.getUrl(false),
50784 params:this.getParams()
50788 success : function(response){
50790 var result = this.processResponse(response);
50791 if(result === true || !result.success || !result.data){
50792 this.failureType = Roo.form.Action.LOAD_FAILURE;
50793 this.form.afterAction(this, false);
50796 this.form.clearInvalid();
50797 this.form.setValues(result.data);
50798 this.form.afterAction(this, true);
50801 handleResponse : function(response){
50802 if(this.form.reader){
50803 var rs = this.form.reader.read(response);
50804 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
50806 success : rs.success,
50810 return Roo.decode(response.responseText);
50814 Roo.form.Action.ACTION_TYPES = {
50815 'load' : Roo.form.Action.Load,
50816 'submit' : Roo.form.Action.Submit
50819 * Ext JS Library 1.1.1
50820 * Copyright(c) 2006-2007, Ext JS, LLC.
50822 * Originally Released Under LGPL - original licence link has changed is not relivant.
50825 * <script type="text/javascript">
50829 * @class Roo.form.Layout
50830 * @extends Roo.Component
50831 * @children Roo.form.Column Roo.form.Row Roo.form.Field Roo.Button Roo.form.TextItem
50832 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
50834 * @param {Object} config Configuration options
50836 Roo.form.Layout = function(config){
50838 if (config.items) {
50839 xitems = config.items;
50840 delete config.items;
50842 Roo.form.Layout.superclass.constructor.call(this, config);
50844 Roo.each(xitems, this.addxtype, this);
50848 Roo.extend(Roo.form.Layout, Roo.Component, {
50850 * @cfg {String/Object} autoCreate
50851 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
50854 * @cfg {String/Object/Function} style
50855 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
50856 * a function which returns such a specification.
50859 * @cfg {String} labelAlign
50860 * Valid values are "left," "top" and "right" (defaults to "left")
50863 * @cfg {Number} labelWidth
50864 * Fixed width in pixels of all field labels (defaults to undefined)
50867 * @cfg {Boolean} clear
50868 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
50872 * @cfg {String} labelSeparator
50873 * The separator to use after field labels (defaults to ':')
50875 labelSeparator : ':',
50877 * @cfg {Boolean} hideLabels
50878 * True to suppress the display of field labels in this layout (defaults to false)
50880 hideLabels : false,
50883 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
50888 onRender : function(ct, position){
50889 if(this.el){ // from markup
50890 this.el = Roo.get(this.el);
50891 }else { // generate
50892 var cfg = this.getAutoCreate();
50893 this.el = ct.createChild(cfg, position);
50896 this.el.applyStyles(this.style);
50898 if(this.labelAlign){
50899 this.el.addClass('x-form-label-'+this.labelAlign);
50901 if(this.hideLabels){
50902 this.labelStyle = "display:none";
50903 this.elementStyle = "padding-left:0;";
50905 if(typeof this.labelWidth == 'number'){
50906 this.labelStyle = "width:"+this.labelWidth+"px;";
50907 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
50909 if(this.labelAlign == 'top'){
50910 this.labelStyle = "width:auto;";
50911 this.elementStyle = "padding-left:0;";
50914 var stack = this.stack;
50915 var slen = stack.length;
50917 if(!this.fieldTpl){
50918 var t = new Roo.Template(
50919 '<div class="x-form-item {5}">',
50920 '<label for="{0}" style="{2}">{1}{4}</label>',
50921 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
50923 '</div><div class="x-form-clear-left"></div>'
50925 t.disableFormats = true;
50927 Roo.form.Layout.prototype.fieldTpl = t;
50929 for(var i = 0; i < slen; i++) {
50930 if(stack[i].isFormField){
50931 this.renderField(stack[i]);
50933 this.renderComponent(stack[i]);
50938 this.el.createChild({cls:'x-form-clear'});
50943 renderField : function(f){
50944 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
50947 f.labelStyle||this.labelStyle||'', //2
50948 this.elementStyle||'', //3
50949 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
50950 f.itemCls||this.itemCls||'' //5
50951 ], true).getPrevSibling());
50955 renderComponent : function(c){
50956 c.render(c.isLayout ? this.el : this.el.createChild());
50959 * Adds a object form elements (using the xtype property as the factory method.)
50960 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
50961 * @param {Object} config
50963 addxtype : function(o)
50965 // create the lement.
50966 o.form = this.form;
50967 var fe = Roo.factory(o, Roo.form);
50968 this.form.allItems.push(fe);
50969 this.stack.push(fe);
50971 if (fe.isFormField) {
50972 this.form.items.add(fe);
50980 * @class Roo.form.Column
50981 * @extends Roo.form.Layout
50982 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
50984 * @param {Object} config Configuration options
50986 Roo.form.Column = function(config){
50987 Roo.form.Column.superclass.constructor.call(this, config);
50990 Roo.extend(Roo.form.Column, Roo.form.Layout, {
50992 * @cfg {Number/String} width
50993 * The fixed width of the column in pixels or CSS value (defaults to "auto")
50996 * @cfg {String/Object} autoCreate
50997 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
51001 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
51004 onRender : function(ct, position){
51005 Roo.form.Column.superclass.onRender.call(this, ct, position);
51007 this.el.setWidth(this.width);
51014 * @class Roo.form.Row
51015 * @extends Roo.form.Layout
51016 * @children Roo.form.Column Roo.form.Row Roo.form.Field Roo.Button Roo.form.TextItem
51017 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
51019 * @param {Object} config Configuration options
51023 Roo.form.Row = function(config){
51024 Roo.form.Row.superclass.constructor.call(this, config);
51027 Roo.extend(Roo.form.Row, Roo.form.Layout, {
51029 * @cfg {Number/String} width
51030 * The fixed width of the column in pixels or CSS value (defaults to "auto")
51033 * @cfg {Number/String} height
51034 * The fixed height of the column in pixels or CSS value (defaults to "auto")
51036 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
51040 onRender : function(ct, position){
51041 //console.log('row render');
51043 var t = new Roo.Template(
51044 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
51045 '<label for="{0}" style="{2}">{1}{4}</label>',
51046 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
51050 t.disableFormats = true;
51052 Roo.form.Layout.prototype.rowTpl = t;
51054 this.fieldTpl = this.rowTpl;
51056 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
51057 var labelWidth = 100;
51059 if ((this.labelAlign != 'top')) {
51060 if (typeof this.labelWidth == 'number') {
51061 labelWidth = this.labelWidth
51063 this.padWidth = 20 + labelWidth;
51067 Roo.form.Column.superclass.onRender.call(this, ct, position);
51069 this.el.setWidth(this.width);
51072 this.el.setHeight(this.height);
51077 renderField : function(f){
51078 f.fieldEl = this.fieldTpl.append(this.el, [
51079 f.id, f.fieldLabel,
51080 f.labelStyle||this.labelStyle||'',
51081 this.elementStyle||'',
51082 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
51083 f.itemCls||this.itemCls||'',
51084 f.width ? f.width + this.padWidth : 160 + this.padWidth
51091 * @class Roo.form.FieldSet
51092 * @extends Roo.form.Layout
51093 * @children Roo.form.Column Roo.form.Row Roo.form.Field Roo.Button Roo.form.TextItem
51094 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
51096 * @param {Object} config Configuration options
51098 Roo.form.FieldSet = function(config){
51099 Roo.form.FieldSet.superclass.constructor.call(this, config);
51102 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
51104 * @cfg {String} legend
51105 * The text to display as the legend for the FieldSet (defaults to '')
51108 * @cfg {String/Object} autoCreate
51109 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
51113 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
51116 onRender : function(ct, position){
51117 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
51119 this.setLegend(this.legend);
51124 setLegend : function(text){
51126 this.el.child('legend').update(text);
51131 * Ext JS Library 1.1.1
51132 * Copyright(c) 2006-2007, Ext JS, LLC.
51134 * Originally Released Under LGPL - original licence link has changed is not relivant.
51137 * <script type="text/javascript">
51140 * @class Roo.form.VTypes
51141 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
51144 Roo.form.VTypes = function(){
51145 // closure these in so they are only created once.
51146 var alpha = /^[a-zA-Z_]+$/;
51147 var alphanum = /^[a-zA-Z0-9_]+$/;
51148 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
51149 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
51151 // All these messages and functions are configurable
51154 * The function used to validate email addresses
51155 * @param {String} value The email address
51157 'email' : function(v){
51158 return email.test(v);
51161 * The error text to display when the email validation function returns false
51164 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
51166 * The keystroke filter mask to be applied on email input
51169 'emailMask' : /[a-z0-9_\.\-@]/i,
51172 * The function used to validate URLs
51173 * @param {String} value The URL
51175 'url' : function(v){
51176 return url.test(v);
51179 * The error text to display when the url validation function returns false
51182 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
51185 * The function used to validate alpha values
51186 * @param {String} value The value
51188 'alpha' : function(v){
51189 return alpha.test(v);
51192 * The error text to display when the alpha validation function returns false
51195 'alphaText' : 'This field should only contain letters and _',
51197 * The keystroke filter mask to be applied on alpha input
51200 'alphaMask' : /[a-z_]/i,
51203 * The function used to validate alphanumeric values
51204 * @param {String} value The value
51206 'alphanum' : function(v){
51207 return alphanum.test(v);
51210 * The error text to display when the alphanumeric validation function returns false
51213 'alphanumText' : 'This field should only contain letters, numbers and _',
51215 * The keystroke filter mask to be applied on alphanumeric input
51218 'alphanumMask' : /[a-z0-9_]/i
51220 }();//<script type="text/javascript">
51223 * @class Roo.form.FCKeditor
51224 * @extends Roo.form.TextArea
51225 * Wrapper around the FCKEditor http://www.fckeditor.net
51227 * Creates a new FCKeditor
51228 * @param {Object} config Configuration options
51230 Roo.form.FCKeditor = function(config){
51231 Roo.form.FCKeditor.superclass.constructor.call(this, config);
51234 * @event editorinit
51235 * Fired when the editor is initialized - you can add extra handlers here..
51236 * @param {FCKeditor} this
51237 * @param {Object} the FCK object.
51244 Roo.form.FCKeditor.editors = { };
51245 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
51247 //defaultAutoCreate : {
51248 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
51252 * @cfg {Object} fck options - see fck manual for details.
51257 * @cfg {Object} fck toolbar set (Basic or Default)
51259 toolbarSet : 'Basic',
51261 * @cfg {Object} fck BasePath
51263 basePath : '/fckeditor/',
51271 onRender : function(ct, position)
51274 this.defaultAutoCreate = {
51276 style:"width:300px;height:60px;",
51277 autocomplete: "new-password"
51280 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
51283 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
51284 if(this.preventScrollbars){
51285 this.el.setStyle("overflow", "hidden");
51287 this.el.setHeight(this.growMin);
51290 //console.log('onrender' + this.getId() );
51291 Roo.form.FCKeditor.editors[this.getId()] = this;
51294 this.replaceTextarea() ;
51298 getEditor : function() {
51299 return this.fckEditor;
51302 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
51303 * @param {Mixed} value The value to set
51307 setValue : function(value)
51309 //console.log('setValue: ' + value);
51311 if(typeof(value) == 'undefined') { // not sure why this is happending...
51314 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
51316 //if(!this.el || !this.getEditor()) {
51317 // this.value = value;
51318 //this.setValue.defer(100,this,[value]);
51322 if(!this.getEditor()) {
51326 this.getEditor().SetData(value);
51333 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
51334 * @return {Mixed} value The field value
51336 getValue : function()
51339 if (this.frame && this.frame.dom.style.display == 'none') {
51340 return Roo.form.FCKeditor.superclass.getValue.call(this);
51343 if(!this.el || !this.getEditor()) {
51345 // this.getValue.defer(100,this);
51350 var value=this.getEditor().GetData();
51351 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
51352 return Roo.form.FCKeditor.superclass.getValue.call(this);
51358 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
51359 * @return {Mixed} value The field value
51361 getRawValue : function()
51363 if (this.frame && this.frame.dom.style.display == 'none') {
51364 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
51367 if(!this.el || !this.getEditor()) {
51368 //this.getRawValue.defer(100,this);
51375 var value=this.getEditor().GetData();
51376 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
51377 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
51381 setSize : function(w,h) {
51385 //if (this.frame && this.frame.dom.style.display == 'none') {
51386 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
51389 //if(!this.el || !this.getEditor()) {
51390 // this.setSize.defer(100,this, [w,h]);
51396 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
51398 this.frame.dom.setAttribute('width', w);
51399 this.frame.dom.setAttribute('height', h);
51400 this.frame.setSize(w,h);
51404 toggleSourceEdit : function(value) {
51408 this.el.dom.style.display = value ? '' : 'none';
51409 this.frame.dom.style.display = value ? 'none' : '';
51414 focus: function(tag)
51416 if (this.frame.dom.style.display == 'none') {
51417 return Roo.form.FCKeditor.superclass.focus.call(this);
51419 if(!this.el || !this.getEditor()) {
51420 this.focus.defer(100,this, [tag]);
51427 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
51428 this.getEditor().Focus();
51430 if (!this.getEditor().Selection.GetSelection()) {
51431 this.focus.defer(100,this, [tag]);
51436 var r = this.getEditor().EditorDocument.createRange();
51437 r.setStart(tgs[0],0);
51438 r.setEnd(tgs[0],0);
51439 this.getEditor().Selection.GetSelection().removeAllRanges();
51440 this.getEditor().Selection.GetSelection().addRange(r);
51441 this.getEditor().Focus();
51448 replaceTextarea : function()
51450 if ( document.getElementById( this.getId() + '___Frame' ) ) {
51453 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
51455 // We must check the elements firstly using the Id and then the name.
51456 var oTextarea = document.getElementById( this.getId() );
51458 var colElementsByName = document.getElementsByName( this.getId() ) ;
51460 oTextarea.style.display = 'none' ;
51462 if ( oTextarea.tabIndex ) {
51463 this.TabIndex = oTextarea.tabIndex ;
51466 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
51467 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
51468 this.frame = Roo.get(this.getId() + '___Frame')
51471 _getConfigHtml : function()
51475 for ( var o in this.fckconfig ) {
51476 sConfig += sConfig.length > 0 ? '&' : '';
51477 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
51480 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
51484 _getIFrameHtml : function()
51486 var sFile = 'fckeditor.html' ;
51487 /* no idea what this is about..
51490 if ( (/fcksource=true/i).test( window.top.location.search ) )
51491 sFile = 'fckeditor.original.html' ;
51496 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
51497 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
51500 var html = '<iframe id="' + this.getId() +
51501 '___Frame" src="' + sLink +
51502 '" width="' + this.width +
51503 '" height="' + this.height + '"' +
51504 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
51505 ' frameborder="0" scrolling="no"></iframe>' ;
51510 _insertHtmlBefore : function( html, element )
51512 if ( element.insertAdjacentHTML ) {
51514 element.insertAdjacentHTML( 'beforeBegin', html ) ;
51516 var oRange = document.createRange() ;
51517 oRange.setStartBefore( element ) ;
51518 var oFragment = oRange.createContextualFragment( html );
51519 element.parentNode.insertBefore( oFragment, element ) ;
51532 //Roo.reg('fckeditor', Roo.form.FCKeditor);
51534 function FCKeditor_OnComplete(editorInstance){
51535 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
51536 f.fckEditor = editorInstance;
51537 //console.log("loaded");
51538 f.fireEvent('editorinit', f, editorInstance);
51558 //<script type="text/javascript">
51560 * @class Roo.form.GridField
51561 * @extends Roo.form.Field
51562 * Embed a grid (or editable grid into a form)
51565 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
51567 * xgrid.store = Roo.data.Store
51568 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
51569 * xgrid.store.reader = Roo.data.JsonReader
51573 * Creates a new GridField
51574 * @param {Object} config Configuration options
51576 Roo.form.GridField = function(config){
51577 Roo.form.GridField.superclass.constructor.call(this, config);
51581 Roo.extend(Roo.form.GridField, Roo.form.Field, {
51583 * @cfg {Number} width - used to restrict width of grid..
51587 * @cfg {Number} height - used to restrict height of grid..
51591 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
51597 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
51598 * {tag: "input", type: "checkbox", autocomplete: "off"})
51600 // defaultAutoCreate : { tag: 'div' },
51601 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'new-password'},
51603 * @cfg {String} addTitle Text to include for adding a title.
51607 onResize : function(){
51608 Roo.form.Field.superclass.onResize.apply(this, arguments);
51611 initEvents : function(){
51612 // Roo.form.Checkbox.superclass.initEvents.call(this);
51613 // has no events...
51618 getResizeEl : function(){
51622 getPositionEl : function(){
51627 onRender : function(ct, position){
51629 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
51630 var style = this.style;
51633 Roo.form.GridField.superclass.onRender.call(this, ct, position);
51634 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
51635 this.viewEl = this.wrap.createChild({ tag: 'div' });
51637 this.viewEl.applyStyles(style);
51640 this.viewEl.setWidth(this.width);
51643 this.viewEl.setHeight(this.height);
51645 //if(this.inputValue !== undefined){
51646 //this.setValue(this.value);
51649 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
51652 this.grid.render();
51653 this.grid.getDataSource().on('remove', this.refreshValue, this);
51654 this.grid.getDataSource().on('update', this.refreshValue, this);
51655 this.grid.on('afteredit', this.refreshValue, this);
51661 * Sets the value of the item.
51662 * @param {String} either an object or a string..
51664 setValue : function(v){
51666 v = v || []; // empty set..
51667 // this does not seem smart - it really only affects memoryproxy grids..
51668 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
51669 var ds = this.grid.getDataSource();
51670 // assumes a json reader..
51672 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
51673 ds.loadData( data);
51675 // clear selection so it does not get stale.
51676 if (this.grid.sm) {
51677 this.grid.sm.clearSelections();
51680 Roo.form.GridField.superclass.setValue.call(this, v);
51681 this.refreshValue();
51682 // should load data in the grid really....
51686 refreshValue: function() {
51688 this.grid.getDataSource().each(function(r) {
51691 this.el.dom.value = Roo.encode(val);
51699 * Ext JS Library 1.1.1
51700 * Copyright(c) 2006-2007, Ext JS, LLC.
51702 * Originally Released Under LGPL - original licence link has changed is not relivant.
51705 * <script type="text/javascript">
51708 * @class Roo.form.DisplayField
51709 * @extends Roo.form.Field
51710 * A generic Field to display non-editable data.
51711 * @cfg {Boolean} closable (true|false) default false
51713 * Creates a new Display Field item.
51714 * @param {Object} config Configuration options
51716 Roo.form.DisplayField = function(config){
51717 Roo.form.DisplayField.superclass.constructor.call(this, config);
51722 * Fires after the click the close btn
51723 * @param {Roo.form.DisplayField} this
51729 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
51730 inputType: 'hidden',
51736 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
51738 focusClass : undefined,
51740 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
51742 fieldClass: 'x-form-field',
51745 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
51747 valueRenderer: undefined,
51751 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
51752 * {tag: "input", type: "checkbox", autocomplete: "off"})
51755 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
51759 onResize : function(){
51760 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
51764 initEvents : function(){
51765 // Roo.form.Checkbox.superclass.initEvents.call(this);
51766 // has no events...
51769 this.closeEl.on('click', this.onClose, this);
51775 getResizeEl : function(){
51779 getPositionEl : function(){
51784 onRender : function(ct, position){
51786 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
51787 //if(this.inputValue !== undefined){
51788 this.wrap = this.el.wrap();
51790 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
51793 this.closeEl = this.wrap.createChild({ tag: 'div', cls: 'x-dlg-close'});
51796 if (this.bodyStyle) {
51797 this.viewEl.applyStyles(this.bodyStyle);
51799 //this.viewEl.setStyle('padding', '2px');
51801 this.setValue(this.value);
51806 initValue : Roo.emptyFn,
51811 onClick : function(){
51816 * Sets the checked state of the checkbox.
51817 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
51819 setValue : function(v){
51821 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
51822 // this might be called before we have a dom element..
51823 if (!this.viewEl) {
51826 this.viewEl.dom.innerHTML = html;
51827 Roo.form.DisplayField.superclass.setValue.call(this, v);
51831 onClose : function(e)
51833 e.preventDefault();
51835 this.fireEvent('close', this);
51844 * @class Roo.form.DayPicker
51845 * @extends Roo.form.Field
51846 * A Day picker show [M] [T] [W] ....
51848 * Creates a new Day Picker
51849 * @param {Object} config Configuration options
51851 Roo.form.DayPicker= function(config){
51852 Roo.form.DayPicker.superclass.constructor.call(this, config);
51856 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
51858 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
51860 focusClass : undefined,
51862 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
51864 fieldClass: "x-form-field",
51867 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
51868 * {tag: "input", type: "checkbox", autocomplete: "off"})
51870 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "new-password"},
51873 actionMode : 'viewEl',
51877 inputType : 'hidden',
51880 inputElement: false, // real input element?
51881 basedOn: false, // ????
51883 isFormField: true, // not sure where this is needed!!!!
51885 onResize : function(){
51886 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
51887 if(!this.boxLabel){
51888 this.el.alignTo(this.wrap, 'c-c');
51892 initEvents : function(){
51893 Roo.form.Checkbox.superclass.initEvents.call(this);
51894 this.el.on("click", this.onClick, this);
51895 this.el.on("change", this.onClick, this);
51899 getResizeEl : function(){
51903 getPositionEl : function(){
51909 onRender : function(ct, position){
51910 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
51912 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
51914 var r1 = '<table><tr>';
51915 var r2 = '<tr class="x-form-daypick-icons">';
51916 for (var i=0; i < 7; i++) {
51917 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
51918 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
51921 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
51922 viewEl.select('img').on('click', this.onClick, this);
51923 this.viewEl = viewEl;
51926 // this will not work on Chrome!!!
51927 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
51928 this.el.on('propertychange', this.setFromHidden, this); //ie
51936 initValue : Roo.emptyFn,
51939 * Returns the checked state of the checkbox.
51940 * @return {Boolean} True if checked, else false
51942 getValue : function(){
51943 return this.el.dom.value;
51948 onClick : function(e){
51949 //this.setChecked(!this.checked);
51950 Roo.get(e.target).toggleClass('x-menu-item-checked');
51951 this.refreshValue();
51952 //if(this.el.dom.checked != this.checked){
51953 // this.setValue(this.el.dom.checked);
51958 refreshValue : function()
51961 this.viewEl.select('img',true).each(function(e,i,n) {
51962 val += e.is(".x-menu-item-checked") ? String(n) : '';
51964 this.setValue(val, true);
51968 * Sets the checked state of the checkbox.
51969 * On is always based on a string comparison between inputValue and the param.
51970 * @param {Boolean/String} value - the value to set
51971 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
51973 setValue : function(v,suppressEvent){
51974 if (!this.el.dom) {
51977 var old = this.el.dom.value ;
51978 this.el.dom.value = v;
51979 if (suppressEvent) {
51983 // update display..
51984 this.viewEl.select('img',true).each(function(e,i,n) {
51986 var on = e.is(".x-menu-item-checked");
51987 var newv = v.indexOf(String(n)) > -1;
51989 e.toggleClass('x-menu-item-checked');
51995 this.fireEvent('change', this, v, old);
52000 // handle setting of hidden value by some other method!!?!?
52001 setFromHidden: function()
52006 //console.log("SET FROM HIDDEN");
52007 //alert('setFrom hidden');
52008 this.setValue(this.el.dom.value);
52011 onDestroy : function()
52014 Roo.get(this.viewEl).remove();
52017 Roo.form.DayPicker.superclass.onDestroy.call(this);
52021 * RooJS Library 1.1.1
52022 * Copyright(c) 2008-2011 Alan Knowles
52029 * @class Roo.form.ComboCheck
52030 * @extends Roo.form.ComboBox
52031 * A combobox for multiple select items.
52033 * FIXME - could do with a reset button..
52036 * Create a new ComboCheck
52037 * @param {Object} config Configuration options
52039 Roo.form.ComboCheck = function(config){
52040 Roo.form.ComboCheck.superclass.constructor.call(this, config);
52041 // should verify some data...
52043 // hiddenName = required..
52044 // displayField = required
52045 // valudField == required
52046 var req= [ 'hiddenName', 'displayField', 'valueField' ];
52048 Roo.each(req, function(e) {
52049 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
52050 throw "Roo.form.ComboCheck : missing value for: " + e;
52057 Roo.extend(Roo.form.ComboCheck, Roo.form.ComboBox, {
52062 selectedClass: 'x-menu-item-checked',
52065 onRender : function(ct, position){
52071 var cls = 'x-combo-list';
52074 this.tpl = new Roo.Template({
52075 html : '<div class="'+cls+'-item x-menu-check-item">' +
52076 '<img class="x-menu-item-icon" style="margin: 0px;" src="' + Roo.BLANK_IMAGE_URL + '">' +
52077 '<span>{' + this.displayField + '}</span>' +
52084 Roo.form.ComboCheck.superclass.onRender.call(this, ct, position);
52085 this.view.singleSelect = false;
52086 this.view.multiSelect = true;
52087 this.view.toggleSelect = true;
52088 this.pageTb.add(new Roo.Toolbar.Fill(), {
52091 handler: function()
52098 onViewOver : function(e, t){
52104 onViewClick : function(doFocus,index){
52108 select: function () {
52109 //Roo.log("SELECT CALLED");
52112 selectByValue : function(xv, scrollIntoView){
52113 var ar = this.getValueArray();
52116 Roo.each(ar, function(v) {
52117 if(v === undefined || v === null){
52120 var r = this.findRecord(this.valueField, v);
52122 sels.push(this.store.indexOf(r))
52126 this.view.select(sels);
52132 onSelect : function(record, index){
52133 // Roo.log("onselect Called");
52134 // this is only called by the clear button now..
52135 this.view.clearSelections();
52136 this.setValue('[]');
52137 if (this.value != this.valueBefore) {
52138 this.fireEvent('change', this, this.value, this.valueBefore);
52139 this.valueBefore = this.value;
52142 getValueArray : function()
52147 //Roo.log(this.value);
52148 if (typeof(this.value) == 'undefined') {
52151 var ar = Roo.decode(this.value);
52152 return ar instanceof Array ? ar : []; //?? valid?
52155 Roo.log(e + "\nRoo.form.ComboCheck:getValueArray invalid data:" + this.getValue());
52160 expand : function ()
52163 Roo.form.ComboCheck.superclass.expand.call(this);
52164 this.valueBefore = typeof(this.value) == 'undefined' ? '' : this.value;
52165 //this.valueBefore = typeof(this.valueBefore) == 'undefined' ? '' : this.valueBefore;
52170 collapse : function(){
52171 Roo.form.ComboCheck.superclass.collapse.call(this);
52172 var sl = this.view.getSelectedIndexes();
52173 var st = this.store;
52177 Roo.each(sl, function(i) {
52179 nv.push(r.get(this.valueField));
52181 this.setValue(Roo.encode(nv));
52182 if (this.value != this.valueBefore) {
52184 this.fireEvent('change', this, this.value, this.valueBefore);
52185 this.valueBefore = this.value;
52190 setValue : function(v){
52194 var vals = this.getValueArray();
52196 Roo.each(vals, function(k) {
52197 var r = this.findRecord(this.valueField, k);
52199 tv.push(r.data[this.displayField]);
52200 }else if(this.valueNotFoundText !== undefined){
52201 tv.push( this.valueNotFoundText );
52206 Roo.form.ComboBox.superclass.setValue.call(this, tv.join(', '));
52207 this.hiddenField.value = v;
52213 * Ext JS Library 1.1.1
52214 * Copyright(c) 2006-2007, Ext JS, LLC.
52216 * Originally Released Under LGPL - original licence link has changed is not relivant.
52219 * <script type="text/javascript">
52223 * @class Roo.form.Signature
52224 * @extends Roo.form.Field
52228 * @param {Object} config Configuration options
52231 Roo.form.Signature = function(config){
52232 Roo.form.Signature.superclass.constructor.call(this, config);
52234 this.addEvents({// not in used??
52237 * Fires when the 'confirm' icon is pressed (add a listener to enable add button)
52238 * @param {Roo.form.Signature} combo This combo box
52243 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
52244 * @param {Roo.form.ComboBox} combo This combo box
52245 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
52251 Roo.extend(Roo.form.Signature, Roo.form.Field, {
52253 * @cfg {Object} labels Label to use when rendering a form.
52257 * confirm : "Confirm"
52262 confirm : "Confirm"
52265 * @cfg {Number} width The signature panel width (defaults to 300)
52269 * @cfg {Number} height The signature panel height (defaults to 100)
52273 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to false)
52275 allowBlank : false,
52278 // {Object} signPanel The signature SVG panel element (defaults to {})
52280 // {Boolean} isMouseDown False to validate that the mouse down event (defaults to false)
52281 isMouseDown : false,
52282 // {Boolean} isConfirmed validate the signature is confirmed or not for submitting form (defaults to false)
52283 isConfirmed : false,
52284 // {String} signatureTmp SVG mapping string (defaults to empty string)
52288 defaultAutoCreate : { // modified by initCompnoent..
52294 onRender : function(ct, position){
52296 Roo.form.Signature.superclass.onRender.call(this, ct, position);
52298 this.wrap = this.el.wrap({
52299 cls:'x-form-signature-wrap', style : 'width: ' + this.width + 'px', cn:{cls:'x-form-signature'}
52302 this.createToolbar(this);
52303 this.signPanel = this.wrap.createChild({
52305 style: 'width: ' + this.width + 'px; height: ' + this.height + 'px; border: 0;'
52309 this.svgID = Roo.id();
52310 this.svgEl = this.signPanel.createChild({
52311 xmlns : 'http://www.w3.org/2000/svg',
52313 id : this.svgID + "-svg",
52315 height: this.height,
52316 viewBox: '0 0 '+this.width+' '+this.height,
52320 id: this.svgID + "-svg-r",
52322 height: this.height,
52327 id: this.svgID + "-svg-l",
52329 y1: (this.height*0.8), // start set the line in 80% of height
52330 x2: this.width, // end
52331 y2: (this.height*0.8), // end set the line in 80% of height
52333 'stroke-width': "1",
52334 'stroke-dasharray': "3",
52335 'shape-rendering': "crispEdges",
52336 'pointer-events': "none"
52340 id: this.svgID + "-svg-p",
52342 'stroke-width': "3",
52344 'pointer-events': 'none'
52349 this.svgBox = this.svgEl.dom.getScreenCTM();
52351 createSVG : function(){
52352 var svg = this.signPanel;
52353 var r = svg.select('#'+ this.svgID + '-svg-r', true).first().dom;
52356 r.addEventListener('mousedown', function(e) { return t.down(e); }, false);
52357 r.addEventListener('mousemove', function(e) { return t.move(e); }, false);
52358 r.addEventListener('mouseup', function(e) { return t.up(e); }, false);
52359 r.addEventListener('mouseout', function(e) { return t.up(e); }, false);
52360 r.addEventListener('touchstart', function(e) { return t.down(e); }, false);
52361 r.addEventListener('touchmove', function(e) { return t.move(e); }, false);
52362 r.addEventListener('touchend', function(e) { return t.up(e); }, false);
52365 isTouchEvent : function(e){
52366 return e.type.match(/^touch/);
52368 getCoords : function (e) {
52369 var pt = this.svgEl.dom.createSVGPoint();
52372 if (this.isTouchEvent(e)) {
52373 pt.x = e.targetTouches[0].clientX;
52374 pt.y = e.targetTouches[0].clientY;
52376 var a = this.svgEl.dom.getScreenCTM();
52377 var b = a.inverse();
52378 var mx = pt.matrixTransform(b);
52379 return mx.x + ',' + mx.y;
52381 //mouse event headler
52382 down : function (e) {
52383 this.signatureTmp += 'M' + this.getCoords(e) + ' ';
52384 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr('d', this.signatureTmp);
52386 this.isMouseDown = true;
52388 e.preventDefault();
52390 move : function (e) {
52391 if (this.isMouseDown) {
52392 this.signatureTmp += 'L' + this.getCoords(e) + ' ';
52393 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', this.signatureTmp);
52396 e.preventDefault();
52398 up : function (e) {
52399 this.isMouseDown = false;
52400 var sp = this.signatureTmp.split(' ');
52403 if(!sp[sp.length-2].match(/^L/)){
52407 this.signatureTmp = sp.join(" ");
52410 if(this.getValue() != this.signatureTmp){
52411 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
52412 this.isConfirmed = false;
52414 e.preventDefault();
52418 * Protected method that will not generally be called directly. It
52419 * is called when the editor creates its toolbar. Override this method if you need to
52420 * add custom toolbar buttons.
52421 * @param {HtmlEditor} editor
52423 createToolbar : function(editor){
52424 function btn(id, toggle, handler){
52425 var xid = fid + '-'+ id ;
52429 cls : 'x-btn-icon x-edit-'+id,
52430 enableToggle:toggle !== false,
52431 scope: editor, // was editor...
52432 handler:handler||editor.relayBtnCmd,
52433 clickEvent:'mousedown',
52434 tooltip: etb.buttonTips[id] || undefined, ///tips ???
52440 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
52444 cls : ' x-signature-btn x-signature-'+id,
52445 scope: editor, // was editor...
52446 handler: this.reset,
52447 clickEvent:'mousedown',
52448 text: this.labels.clear
52455 cls : ' x-signature-btn x-signature-'+id,
52456 scope: editor, // was editor...
52457 handler: this.confirmHandler,
52458 clickEvent:'mousedown',
52459 text: this.labels.confirm
52466 * when user is clicked confirm then show this image.....
52468 * @return {String} Image Data URI
52470 getImageDataURI : function(){
52471 var svg = this.svgEl.dom.parentNode.innerHTML;
52472 var src = 'data:image/svg+xml;base64,'+window.btoa(svg);
52477 * @return {Boolean} this.isConfirmed
52479 getConfirmed : function(){
52480 return this.isConfirmed;
52484 * @return {Number} this.width
52486 getWidth : function(){
52491 * @return {Number} this.height
52493 getHeight : function(){
52494 return this.height;
52497 getSignature : function(){
52498 return this.signatureTmp;
52501 reset : function(){
52502 this.signatureTmp = '';
52503 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
52504 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', '');
52505 this.isConfirmed = false;
52506 Roo.form.Signature.superclass.reset.call(this);
52508 setSignature : function(s){
52509 this.signatureTmp = s;
52510 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
52511 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', s);
52513 this.isConfirmed = false;
52514 Roo.form.Signature.superclass.reset.call(this);
52517 // Roo.log(this.signPanel.dom.contentWindow.up())
52520 setConfirmed : function(){
52524 // Roo.log(Roo.get(this.signPanel.dom.contentWindow.r).attr('fill', '#cfc'));
52527 confirmHandler : function(){
52528 if(!this.getSignature()){
52532 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#cfc');
52533 this.setValue(this.getSignature());
52534 this.isConfirmed = true;
52536 this.fireEvent('confirm', this);
52539 // Subclasses should provide the validation implementation by overriding this
52540 validateValue : function(value){
52541 if(this.allowBlank){
52545 if(this.isConfirmed){
52552 * Ext JS Library 1.1.1
52553 * Copyright(c) 2006-2007, Ext JS, LLC.
52555 * Originally Released Under LGPL - original licence link has changed is not relivant.
52558 * <script type="text/javascript">
52563 * @class Roo.form.ComboBox
52564 * @extends Roo.form.TriggerField
52565 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
52567 * Create a new ComboBox.
52568 * @param {Object} config Configuration options
52570 Roo.form.Select = function(config){
52571 Roo.form.Select.superclass.constructor.call(this, config);
52575 Roo.extend(Roo.form.Select , Roo.form.ComboBox, {
52577 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
52580 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
52581 * rendering into an Roo.Editor, defaults to false)
52584 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
52585 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
52588 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
52591 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
52592 * the dropdown list (defaults to undefined, with no header element)
52596 * @cfg {String/Roo.Template} tpl The template to use to render the output
52600 defaultAutoCreate : {tag: "select" },
52602 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
52604 listWidth: undefined,
52606 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
52607 * mode = 'remote' or 'text' if mode = 'local')
52609 displayField: undefined,
52611 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
52612 * mode = 'remote' or 'value' if mode = 'local').
52613 * Note: use of a valueField requires the user make a selection
52614 * in order for a value to be mapped.
52616 valueField: undefined,
52620 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
52621 * field's data value (defaults to the underlying DOM element's name)
52623 hiddenName: undefined,
52625 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
52629 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
52631 selectedClass: 'x-combo-selected',
52633 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
52634 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
52635 * which displays a downward arrow icon).
52637 triggerClass : 'x-form-arrow-trigger',
52639 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
52643 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
52644 * anchor positions (defaults to 'tl-bl')
52646 listAlign: 'tl-bl?',
52648 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
52652 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
52653 * query specified by the allQuery config option (defaults to 'query')
52655 triggerAction: 'query',
52657 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
52658 * (defaults to 4, does not apply if editable = false)
52662 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
52663 * delay (typeAheadDelay) if it matches a known value (defaults to false)
52667 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
52668 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
52672 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
52673 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
52677 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
52678 * when editable = true (defaults to false)
52680 selectOnFocus:false,
52682 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
52684 queryParam: 'query',
52686 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
52687 * when mode = 'remote' (defaults to 'Loading...')
52689 loadingText: 'Loading...',
52691 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
52695 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
52699 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
52700 * traditional select (defaults to true)
52704 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
52708 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
52712 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
52713 * listWidth has a higher value)
52717 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
52718 * allow the user to set arbitrary text into the field (defaults to false)
52720 forceSelection:false,
52722 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
52723 * if typeAhead = true (defaults to 250)
52725 typeAheadDelay : 250,
52727 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
52728 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
52730 valueNotFoundText : undefined,
52733 * @cfg {String} defaultValue The value displayed after loading the store.
52738 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
52740 blockFocus : false,
52743 * @cfg {Boolean} disableClear Disable showing of clear button.
52745 disableClear : false,
52747 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
52749 alwaysQuery : false,
52755 // element that contains real text value.. (when hidden is used..)
52758 onRender : function(ct, position){
52759 Roo.form.Field.prototype.onRender.call(this, ct, position);
52762 this.store.on('beforeload', this.onBeforeLoad, this);
52763 this.store.on('load', this.onLoad, this);
52764 this.store.on('loadexception', this.onLoadException, this);
52765 this.store.load({});
52773 initEvents : function(){
52774 //Roo.form.ComboBox.superclass.initEvents.call(this);
52778 onDestroy : function(){
52781 this.store.un('beforeload', this.onBeforeLoad, this);
52782 this.store.un('load', this.onLoad, this);
52783 this.store.un('loadexception', this.onLoadException, this);
52785 //Roo.form.ComboBox.superclass.onDestroy.call(this);
52789 fireKey : function(e){
52790 if(e.isNavKeyPress() && !this.list.isVisible()){
52791 this.fireEvent("specialkey", this, e);
52796 onResize: function(w, h){
52804 * Allow or prevent the user from directly editing the field text. If false is passed,
52805 * the user will only be able to select from the items defined in the dropdown list. This method
52806 * is the runtime equivalent of setting the 'editable' config option at config time.
52807 * @param {Boolean} value True to allow the user to directly edit the field text
52809 setEditable : function(value){
52814 onBeforeLoad : function(){
52816 Roo.log("Select before load");
52819 this.innerList.update(this.loadingText ?
52820 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
52821 //this.restrictHeight();
52822 this.selectedIndex = -1;
52826 onLoad : function(){
52829 var dom = this.el.dom;
52830 dom.innerHTML = '';
52831 var od = dom.ownerDocument;
52833 if (this.emptyText) {
52834 var op = od.createElement('option');
52835 op.setAttribute('value', '');
52836 op.innerHTML = String.format('{0}', this.emptyText);
52837 dom.appendChild(op);
52839 if(this.store.getCount() > 0){
52841 var vf = this.valueField;
52842 var df = this.displayField;
52843 this.store.data.each(function(r) {
52844 // which colmsn to use... testing - cdoe / title..
52845 var op = od.createElement('option');
52846 op.setAttribute('value', r.data[vf]);
52847 op.innerHTML = String.format('{0}', r.data[df]);
52848 dom.appendChild(op);
52850 if (typeof(this.defaultValue != 'undefined')) {
52851 this.setValue(this.defaultValue);
52856 //this.onEmptyResults();
52861 onLoadException : function()
52863 dom.innerHTML = '';
52865 Roo.log("Select on load exception");
52869 Roo.log(this.store.reader.jsonData);
52870 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
52871 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
52877 onTypeAhead : function(){
52882 onSelect : function(record, index){
52883 Roo.log('on select?');
52885 if(this.fireEvent('beforeselect', this, record, index) !== false){
52886 this.setFromData(index > -1 ? record.data : false);
52888 this.fireEvent('select', this, record, index);
52893 * Returns the currently selected field value or empty string if no value is set.
52894 * @return {String} value The selected value
52896 getValue : function(){
52897 var dom = this.el.dom;
52898 this.value = dom.options[dom.selectedIndex].value;
52904 * Clears any text/value currently set in the field
52906 clearValue : function(){
52908 this.el.dom.selectedIndex = this.emptyText ? 0 : -1;
52913 * Sets the specified value into the field. If the value finds a match, the corresponding record text
52914 * will be displayed in the field. If the value does not match the data value of an existing item,
52915 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
52916 * Otherwise the field will be blank (although the value will still be set).
52917 * @param {String} value The value to match
52919 setValue : function(v){
52920 var d = this.el.dom;
52921 for (var i =0; i < d.options.length;i++) {
52922 if (v == d.options[i].value) {
52923 d.selectedIndex = i;
52931 * @property {Object} the last set data for the element
52936 * Sets the value of the field based on a object which is related to the record format for the store.
52937 * @param {Object} value the value to set as. or false on reset?
52939 setFromData : function(o){
52940 Roo.log('setfrom data?');
52946 reset : function(){
52950 findRecord : function(prop, value){
52955 if(this.store.getCount() > 0){
52956 this.store.each(function(r){
52957 if(r.data[prop] == value){
52967 getName: function()
52969 // returns hidden if it's set..
52970 if (!this.rendered) {return ''};
52971 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
52979 onEmptyResults : function(){
52980 Roo.log('empty results');
52985 * Returns true if the dropdown list is expanded, else false.
52987 isExpanded : function(){
52992 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
52993 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
52994 * @param {String} value The data value of the item to select
52995 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
52996 * selected item if it is not currently in view (defaults to true)
52997 * @return {Boolean} True if the value matched an item in the list, else false
52999 selectByValue : function(v, scrollIntoView){
53000 Roo.log('select By Value');
53003 if(v !== undefined && v !== null){
53004 var r = this.findRecord(this.valueField || this.displayField, v);
53006 this.select(this.store.indexOf(r), scrollIntoView);
53014 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
53015 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
53016 * @param {Number} index The zero-based index of the list item to select
53017 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
53018 * selected item if it is not currently in view (defaults to true)
53020 select : function(index, scrollIntoView){
53021 Roo.log('select ');
53024 this.selectedIndex = index;
53025 this.view.select(index);
53026 if(scrollIntoView !== false){
53027 var el = this.view.getNode(index);
53029 this.innerList.scrollChildIntoView(el, false);
53037 validateBlur : function(){
53044 initQuery : function(){
53045 this.doQuery(this.getRawValue());
53049 doForce : function(){
53050 if(this.el.dom.value.length > 0){
53051 this.el.dom.value =
53052 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
53058 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
53059 * query allowing the query action to be canceled if needed.
53060 * @param {String} query The SQL query to execute
53061 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
53062 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
53063 * saved in the current store (defaults to false)
53065 doQuery : function(q, forceAll){
53067 Roo.log('doQuery?');
53068 if(q === undefined || q === null){
53073 forceAll: forceAll,
53077 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
53081 forceAll = qe.forceAll;
53082 if(forceAll === true || (q.length >= this.minChars)){
53083 if(this.lastQuery != q || this.alwaysQuery){
53084 this.lastQuery = q;
53085 if(this.mode == 'local'){
53086 this.selectedIndex = -1;
53088 this.store.clearFilter();
53090 this.store.filter(this.displayField, q);
53094 this.store.baseParams[this.queryParam] = q;
53096 params: this.getParams(q)
53101 this.selectedIndex = -1;
53108 getParams : function(q){
53110 //p[this.queryParam] = q;
53113 p.limit = this.pageSize;
53119 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
53121 collapse : function(){
53126 collapseIf : function(e){
53131 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
53133 expand : function(){
53141 * @cfg {Boolean} grow
53145 * @cfg {Number} growMin
53149 * @cfg {Number} growMax
53157 setWidth : function()
53161 getResizeEl : function(){
53164 });//<script type="text/javasscript">
53168 * @class Roo.DDView
53169 * A DnD enabled version of Roo.View.
53170 * @param {Element/String} container The Element in which to create the View.
53171 * @param {String} tpl The template string used to create the markup for each element of the View
53172 * @param {Object} config The configuration properties. These include all the config options of
53173 * {@link Roo.View} plus some specific to this class.<br>
53175 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
53176 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
53178 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
53179 .x-view-drag-insert-above {
53180 border-top:1px dotted #3366cc;
53182 .x-view-drag-insert-below {
53183 border-bottom:1px dotted #3366cc;
53189 Roo.DDView = function(container, tpl, config) {
53190 Roo.DDView.superclass.constructor.apply(this, arguments);
53191 this.getEl().setStyle("outline", "0px none");
53192 this.getEl().unselectable();
53193 if (this.dragGroup) {
53194 this.setDraggable(this.dragGroup.split(","));
53196 if (this.dropGroup) {
53197 this.setDroppable(this.dropGroup.split(","));
53199 if (this.deletable) {
53200 this.setDeletable();
53202 this.isDirtyFlag = false;
53208 Roo.extend(Roo.DDView, Roo.View, {
53209 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
53210 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
53211 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
53212 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
53216 reset: Roo.emptyFn,
53218 clearInvalid: Roo.form.Field.prototype.clearInvalid,
53220 validate: function() {
53224 destroy: function() {
53225 this.purgeListeners();
53226 this.getEl.removeAllListeners();
53227 this.getEl().remove();
53228 if (this.dragZone) {
53229 if (this.dragZone.destroy) {
53230 this.dragZone.destroy();
53233 if (this.dropZone) {
53234 if (this.dropZone.destroy) {
53235 this.dropZone.destroy();
53240 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
53241 getName: function() {
53245 /** Loads the View from a JSON string representing the Records to put into the Store. */
53246 setValue: function(v) {
53248 throw "DDView.setValue(). DDView must be constructed with a valid Store";
53251 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
53252 this.store.proxy = new Roo.data.MemoryProxy(data);
53256 /** @return {String} a parenthesised list of the ids of the Records in the View. */
53257 getValue: function() {
53259 this.store.each(function(rec) {
53260 result += rec.id + ',';
53262 return result.substr(0, result.length - 1) + ')';
53265 getIds: function() {
53266 var i = 0, result = new Array(this.store.getCount());
53267 this.store.each(function(rec) {
53268 result[i++] = rec.id;
53273 isDirty: function() {
53274 return this.isDirtyFlag;
53278 * Part of the Roo.dd.DropZone interface. If no target node is found, the
53279 * whole Element becomes the target, and this causes the drop gesture to append.
53281 getTargetFromEvent : function(e) {
53282 var target = e.getTarget();
53283 while ((target !== null) && (target.parentNode != this.el.dom)) {
53284 target = target.parentNode;
53287 target = this.el.dom.lastChild || this.el.dom;
53293 * Create the drag data which consists of an object which has the property "ddel" as
53294 * the drag proxy element.
53296 getDragData : function(e) {
53297 var target = this.findItemFromChild(e.getTarget());
53299 this.handleSelection(e);
53300 var selNodes = this.getSelectedNodes();
53303 copy: this.copy || (this.allowCopy && e.ctrlKey),
53307 var selectedIndices = this.getSelectedIndexes();
53308 for (var i = 0; i < selectedIndices.length; i++) {
53309 dragData.records.push(this.store.getAt(selectedIndices[i]));
53311 if (selNodes.length == 1) {
53312 dragData.ddel = target.cloneNode(true); // the div element
53314 var div = document.createElement('div'); // create the multi element drag "ghost"
53315 div.className = 'multi-proxy';
53316 for (var i = 0, len = selNodes.length; i < len; i++) {
53317 div.appendChild(selNodes[i].cloneNode(true));
53319 dragData.ddel = div;
53321 //console.log(dragData)
53322 //console.log(dragData.ddel.innerHTML)
53325 //console.log('nodragData')
53329 /** Specify to which ddGroup items in this DDView may be dragged. */
53330 setDraggable: function(ddGroup) {
53331 if (ddGroup instanceof Array) {
53332 Roo.each(ddGroup, this.setDraggable, this);
53335 if (this.dragZone) {
53336 this.dragZone.addToGroup(ddGroup);
53338 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
53339 containerScroll: true,
53343 // Draggability implies selection. DragZone's mousedown selects the element.
53344 if (!this.multiSelect) { this.singleSelect = true; }
53346 // Wire the DragZone's handlers up to methods in *this*
53347 this.dragZone.getDragData = this.getDragData.createDelegate(this);
53351 /** Specify from which ddGroup this DDView accepts drops. */
53352 setDroppable: function(ddGroup) {
53353 if (ddGroup instanceof Array) {
53354 Roo.each(ddGroup, this.setDroppable, this);
53357 if (this.dropZone) {
53358 this.dropZone.addToGroup(ddGroup);
53360 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
53361 containerScroll: true,
53365 // Wire the DropZone's handlers up to methods in *this*
53366 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
53367 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
53368 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
53369 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
53370 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
53374 /** Decide whether to drop above or below a View node. */
53375 getDropPoint : function(e, n, dd){
53376 if (n == this.el.dom) { return "above"; }
53377 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
53378 var c = t + (b - t) / 2;
53379 var y = Roo.lib.Event.getPageY(e);
53387 onNodeEnter : function(n, dd, e, data){
53391 onNodeOver : function(n, dd, e, data){
53392 var pt = this.getDropPoint(e, n, dd);
53393 // set the insert point style on the target node
53394 var dragElClass = this.dropNotAllowed;
53397 if (pt == "above"){
53398 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
53399 targetElClass = "x-view-drag-insert-above";
53401 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
53402 targetElClass = "x-view-drag-insert-below";
53404 if (this.lastInsertClass != targetElClass){
53405 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
53406 this.lastInsertClass = targetElClass;
53409 return dragElClass;
53412 onNodeOut : function(n, dd, e, data){
53413 this.removeDropIndicators(n);
53416 onNodeDrop : function(n, dd, e, data){
53417 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
53420 var pt = this.getDropPoint(e, n, dd);
53421 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
53422 if (pt == "below") { insertAt++; }
53423 for (var i = 0; i < data.records.length; i++) {
53424 var r = data.records[i];
53425 var dup = this.store.getById(r.id);
53426 if (dup && (dd != this.dragZone)) {
53427 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
53430 this.store.insert(insertAt++, r.copy());
53432 data.source.isDirtyFlag = true;
53434 this.store.insert(insertAt++, r);
53436 this.isDirtyFlag = true;
53439 this.dragZone.cachedTarget = null;
53443 removeDropIndicators : function(n){
53445 Roo.fly(n).removeClass([
53446 "x-view-drag-insert-above",
53447 "x-view-drag-insert-below"]);
53448 this.lastInsertClass = "_noclass";
53453 * Utility method. Add a delete option to the DDView's context menu.
53454 * @param {String} imageUrl The URL of the "delete" icon image.
53456 setDeletable: function(imageUrl) {
53457 if (!this.singleSelect && !this.multiSelect) {
53458 this.singleSelect = true;
53460 var c = this.getContextMenu();
53461 this.contextMenu.on("itemclick", function(item) {
53464 this.remove(this.getSelectedIndexes());
53468 this.contextMenu.add({
53475 /** Return the context menu for this DDView. */
53476 getContextMenu: function() {
53477 if (!this.contextMenu) {
53478 // Create the View's context menu
53479 this.contextMenu = new Roo.menu.Menu({
53480 id: this.id + "-contextmenu"
53482 this.el.on("contextmenu", this.showContextMenu, this);
53484 return this.contextMenu;
53487 disableContextMenu: function() {
53488 if (this.contextMenu) {
53489 this.el.un("contextmenu", this.showContextMenu, this);
53493 showContextMenu: function(e, item) {
53494 item = this.findItemFromChild(e.getTarget());
53497 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
53498 this.contextMenu.showAt(e.getXY());
53503 * Remove {@link Roo.data.Record}s at the specified indices.
53504 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
53506 remove: function(selectedIndices) {
53507 selectedIndices = [].concat(selectedIndices);
53508 for (var i = 0; i < selectedIndices.length; i++) {
53509 var rec = this.store.getAt(selectedIndices[i]);
53510 this.store.remove(rec);
53515 * Double click fires the event, but also, if this is draggable, and there is only one other
53516 * related DropZone, it transfers the selected node.
53518 onDblClick : function(e){
53519 var item = this.findItemFromChild(e.getTarget());
53521 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
53524 if (this.dragGroup) {
53525 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
53526 while (targets.indexOf(this.dropZone) > -1) {
53527 targets.remove(this.dropZone);
53529 if (targets.length == 1) {
53530 this.dragZone.cachedTarget = null;
53531 var el = Roo.get(targets[0].getEl());
53532 var box = el.getBox(true);
53533 targets[0].onNodeDrop(el.dom, {
53535 xy: [box.x, box.y + box.height - 1]
53536 }, null, this.getDragData(e));
53542 handleSelection: function(e) {
53543 this.dragZone.cachedTarget = null;
53544 var item = this.findItemFromChild(e.getTarget());
53546 this.clearSelections(true);
53549 if (item && (this.multiSelect || this.singleSelect)){
53550 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
53551 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
53552 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
53553 this.unselect(item);
53555 this.select(item, this.multiSelect && e.ctrlKey);
53556 this.lastSelection = item;
53561 onItemClick : function(item, index, e){
53562 if(this.fireEvent("beforeclick", this, index, item, e) === false){
53568 unselect : function(nodeInfo, suppressEvent){
53569 var node = this.getNode(nodeInfo);
53570 if(node && this.isSelected(node)){
53571 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
53572 Roo.fly(node).removeClass(this.selectedClass);
53573 this.selections.remove(node);
53574 if(!suppressEvent){
53575 this.fireEvent("selectionchange", this, this.selections);
53583 * Ext JS Library 1.1.1
53584 * Copyright(c) 2006-2007, Ext JS, LLC.
53586 * Originally Released Under LGPL - original licence link has changed is not relivant.
53589 * <script type="text/javascript">
53593 * @class Roo.LayoutManager
53594 * @extends Roo.util.Observable
53595 * Base class for layout managers.
53597 Roo.LayoutManager = function(container, config){
53598 Roo.LayoutManager.superclass.constructor.call(this);
53599 this.el = Roo.get(container);
53600 // ie scrollbar fix
53601 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
53602 document.body.scroll = "no";
53603 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
53604 this.el.position('relative');
53606 this.id = this.el.id;
53607 this.el.addClass("x-layout-container");
53608 /** false to disable window resize monitoring @type Boolean */
53609 this.monitorWindowResize = true;
53614 * Fires when a layout is performed.
53615 * @param {Roo.LayoutManager} this
53619 * @event regionresized
53620 * Fires when the user resizes a region.
53621 * @param {Roo.LayoutRegion} region The resized region
53622 * @param {Number} newSize The new size (width for east/west, height for north/south)
53624 "regionresized" : true,
53626 * @event regioncollapsed
53627 * Fires when a region is collapsed.
53628 * @param {Roo.LayoutRegion} region The collapsed region
53630 "regioncollapsed" : true,
53632 * @event regionexpanded
53633 * Fires when a region is expanded.
53634 * @param {Roo.LayoutRegion} region The expanded region
53636 "regionexpanded" : true
53638 this.updating = false;
53639 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
53642 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
53644 * Returns true if this layout is currently being updated
53645 * @return {Boolean}
53647 isUpdating : function(){
53648 return this.updating;
53652 * Suspend the LayoutManager from doing auto-layouts while
53653 * making multiple add or remove calls
53655 beginUpdate : function(){
53656 this.updating = true;
53660 * Restore auto-layouts and optionally disable the manager from performing a layout
53661 * @param {Boolean} noLayout true to disable a layout update
53663 endUpdate : function(noLayout){
53664 this.updating = false;
53670 layout: function(){
53674 onRegionResized : function(region, newSize){
53675 this.fireEvent("regionresized", region, newSize);
53679 onRegionCollapsed : function(region){
53680 this.fireEvent("regioncollapsed", region);
53683 onRegionExpanded : function(region){
53684 this.fireEvent("regionexpanded", region);
53688 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
53689 * performs box-model adjustments.
53690 * @return {Object} The size as an object {width: (the width), height: (the height)}
53692 getViewSize : function(){
53694 if(this.el.dom != document.body){
53695 size = this.el.getSize();
53697 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
53699 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
53700 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
53705 * Returns the Element this layout is bound to.
53706 * @return {Roo.Element}
53708 getEl : function(){
53713 * Returns the specified region.
53714 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
53715 * @return {Roo.LayoutRegion}
53717 getRegion : function(target){
53718 return this.regions[target.toLowerCase()];
53721 onWindowResize : function(){
53722 if(this.monitorWindowResize){
53728 * Ext JS Library 1.1.1
53729 * Copyright(c) 2006-2007, Ext JS, LLC.
53731 * Originally Released Under LGPL - original licence link has changed is not relivant.
53734 * <script type="text/javascript">
53737 * @class Roo.BorderLayout
53738 * @extends Roo.LayoutManager
53739 * @children Roo.ContentPanel
53740 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
53741 * please see: <br><br>
53742 * <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>
53743 * <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>
53746 var layout = new Roo.BorderLayout(document.body, {
53780 preferredTabWidth: 150
53785 var CP = Roo.ContentPanel;
53787 layout.beginUpdate();
53788 layout.add("north", new CP("north", "North"));
53789 layout.add("south", new CP("south", {title: "South", closable: true}));
53790 layout.add("west", new CP("west", {title: "West"}));
53791 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
53792 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
53793 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
53794 layout.getRegion("center").showPanel("center1");
53795 layout.endUpdate();
53798 <b>The container the layout is rendered into can be either the body element or any other element.
53799 If it is not the body element, the container needs to either be an absolute positioned element,
53800 or you will need to add "position:relative" to the css of the container. You will also need to specify
53801 the container size if it is not the body element.</b>
53804 * Create a new BorderLayout
53805 * @param {String/HTMLElement/Element} container The container this layout is bound to
53806 * @param {Object} config Configuration options
53808 Roo.BorderLayout = function(container, config){
53809 config = config || {};
53810 Roo.BorderLayout.superclass.constructor.call(this, container, config);
53811 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
53812 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
53813 var target = this.factory.validRegions[i];
53814 if(config[target]){
53815 this.addRegion(target, config[target]);
53820 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
53823 * @cfg {Roo.LayoutRegion} east
53826 * @cfg {Roo.LayoutRegion} west
53829 * @cfg {Roo.LayoutRegion} north
53832 * @cfg {Roo.LayoutRegion} south
53835 * @cfg {Roo.LayoutRegion} center
53838 * Creates and adds a new region if it doesn't already exist.
53839 * @param {String} target The target region key (north, south, east, west or center).
53840 * @param {Object} config The regions config object
53841 * @return {BorderLayoutRegion} The new region
53843 addRegion : function(target, config){
53844 if(!this.regions[target]){
53845 var r = this.factory.create(target, this, config);
53846 this.bindRegion(target, r);
53848 return this.regions[target];
53852 bindRegion : function(name, r){
53853 this.regions[name] = r;
53854 r.on("visibilitychange", this.layout, this);
53855 r.on("paneladded", this.layout, this);
53856 r.on("panelremoved", this.layout, this);
53857 r.on("invalidated", this.layout, this);
53858 r.on("resized", this.onRegionResized, this);
53859 r.on("collapsed", this.onRegionCollapsed, this);
53860 r.on("expanded", this.onRegionExpanded, this);
53864 * Performs a layout update.
53866 layout : function(){
53867 if(this.updating) {
53870 var size = this.getViewSize();
53871 var w = size.width;
53872 var h = size.height;
53877 //var x = 0, y = 0;
53879 var rs = this.regions;
53880 var north = rs["north"];
53881 var south = rs["south"];
53882 var west = rs["west"];
53883 var east = rs["east"];
53884 var center = rs["center"];
53885 //if(this.hideOnLayout){ // not supported anymore
53886 //c.el.setStyle("display", "none");
53888 if(north && north.isVisible()){
53889 var b = north.getBox();
53890 var m = north.getMargins();
53891 b.width = w - (m.left+m.right);
53894 centerY = b.height + b.y + m.bottom;
53895 centerH -= centerY;
53896 north.updateBox(this.safeBox(b));
53898 if(south && south.isVisible()){
53899 var b = south.getBox();
53900 var m = south.getMargins();
53901 b.width = w - (m.left+m.right);
53903 var totalHeight = (b.height + m.top + m.bottom);
53904 b.y = h - totalHeight + m.top;
53905 centerH -= totalHeight;
53906 south.updateBox(this.safeBox(b));
53908 if(west && west.isVisible()){
53909 var b = west.getBox();
53910 var m = west.getMargins();
53911 b.height = centerH - (m.top+m.bottom);
53913 b.y = centerY + m.top;
53914 var totalWidth = (b.width + m.left + m.right);
53915 centerX += totalWidth;
53916 centerW -= totalWidth;
53917 west.updateBox(this.safeBox(b));
53919 if(east && east.isVisible()){
53920 var b = east.getBox();
53921 var m = east.getMargins();
53922 b.height = centerH - (m.top+m.bottom);
53923 var totalWidth = (b.width + m.left + m.right);
53924 b.x = w - totalWidth + m.left;
53925 b.y = centerY + m.top;
53926 centerW -= totalWidth;
53927 east.updateBox(this.safeBox(b));
53930 var m = center.getMargins();
53932 x: centerX + m.left,
53933 y: centerY + m.top,
53934 width: centerW - (m.left+m.right),
53935 height: centerH - (m.top+m.bottom)
53937 //if(this.hideOnLayout){
53938 //center.el.setStyle("display", "block");
53940 center.updateBox(this.safeBox(centerBox));
53943 this.fireEvent("layout", this);
53947 safeBox : function(box){
53948 box.width = Math.max(0, box.width);
53949 box.height = Math.max(0, box.height);
53954 * Adds a ContentPanel (or subclass) to this layout.
53955 * @param {String} target The target region key (north, south, east, west or center).
53956 * @param {Roo.ContentPanel} panel The panel to add
53957 * @return {Roo.ContentPanel} The added panel
53959 add : function(target, panel){
53961 target = target.toLowerCase();
53962 return this.regions[target].add(panel);
53966 * Remove a ContentPanel (or subclass) to this layout.
53967 * @param {String} target The target region key (north, south, east, west or center).
53968 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
53969 * @return {Roo.ContentPanel} The removed panel
53971 remove : function(target, panel){
53972 target = target.toLowerCase();
53973 return this.regions[target].remove(panel);
53977 * Searches all regions for a panel with the specified id
53978 * @param {String} panelId
53979 * @return {Roo.ContentPanel} The panel or null if it wasn't found
53981 findPanel : function(panelId){
53982 var rs = this.regions;
53983 for(var target in rs){
53984 if(typeof rs[target] != "function"){
53985 var p = rs[target].getPanel(panelId);
53995 * Searches all regions for a panel with the specified id and activates (shows) it.
53996 * @param {String/ContentPanel} panelId The panels id or the panel itself
53997 * @return {Roo.ContentPanel} The shown panel or null
53999 showPanel : function(panelId) {
54000 var rs = this.regions;
54001 for(var target in rs){
54002 var r = rs[target];
54003 if(typeof r != "function"){
54004 if(r.hasPanel(panelId)){
54005 return r.showPanel(panelId);
54013 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
54014 * @param {Roo.state.Provider} provider (optional) An alternate state provider
54016 restoreState : function(provider){
54018 provider = Roo.state.Manager;
54020 var sm = new Roo.LayoutStateManager();
54021 sm.init(this, provider);
54025 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
54026 * object should contain properties for each region to add ContentPanels to, and each property's value should be
54027 * a valid ContentPanel config object. Example:
54029 // Create the main layout
54030 var layout = new Roo.BorderLayout('main-ct', {
54041 // Create and add multiple ContentPanels at once via configs
54044 id: 'source-files',
54046 title:'Ext Source Files',
54059 * @param {Object} regions An object containing ContentPanel configs by region name
54061 batchAdd : function(regions){
54062 this.beginUpdate();
54063 for(var rname in regions){
54064 var lr = this.regions[rname];
54066 this.addTypedPanels(lr, regions[rname]);
54073 addTypedPanels : function(lr, ps){
54074 if(typeof ps == 'string'){
54075 lr.add(new Roo.ContentPanel(ps));
54077 else if(ps instanceof Array){
54078 for(var i =0, len = ps.length; i < len; i++){
54079 this.addTypedPanels(lr, ps[i]);
54082 else if(!ps.events){ // raw config?
54084 delete ps.el; // prevent conflict
54085 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
54087 else { // panel object assumed!
54092 * Adds a xtype elements to the layout.
54096 xtype : 'ContentPanel',
54103 xtype : 'NestedLayoutPanel',
54109 items : [ ... list of content panels or nested layout panels.. ]
54113 * @param {Object} cfg Xtype definition of item to add.
54115 addxtype : function(cfg)
54117 // basically accepts a pannel...
54118 // can accept a layout region..!?!?
54119 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
54121 if (!cfg.xtype.match(/Panel$/)) {
54126 if (typeof(cfg.region) == 'undefined') {
54127 Roo.log("Failed to add Panel, region was not set");
54131 var region = cfg.region;
54137 xitems = cfg.items;
54144 case 'ContentPanel': // ContentPanel (el, cfg)
54145 case 'ScrollPanel': // ContentPanel (el, cfg)
54147 if(cfg.autoCreate) {
54148 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
54150 var el = this.el.createChild();
54151 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
54154 this.add(region, ret);
54158 case 'TreePanel': // our new panel!
54159 cfg.el = this.el.createChild();
54160 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
54161 this.add(region, ret);
54164 case 'NestedLayoutPanel':
54165 // create a new Layout (which is a Border Layout...
54166 var el = this.el.createChild();
54167 var clayout = cfg.layout;
54169 clayout.items = clayout.items || [];
54170 // replace this exitems with the clayout ones..
54171 xitems = clayout.items;
54174 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
54175 cfg.background = false;
54177 var layout = new Roo.BorderLayout(el, clayout);
54179 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
54180 //console.log('adding nested layout panel ' + cfg.toSource());
54181 this.add(region, ret);
54182 nb = {}; /// find first...
54187 // needs grid and region
54189 //var el = this.getRegion(region).el.createChild();
54190 var el = this.el.createChild();
54191 // create the grid first...
54193 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
54195 if (region == 'center' && this.active ) {
54196 cfg.background = false;
54198 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
54200 this.add(region, ret);
54201 if (cfg.background) {
54202 ret.on('activate', function(gp) {
54203 if (!gp.grid.rendered) {
54218 if (typeof(Roo[cfg.xtype]) != 'undefined') {
54220 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
54221 this.add(region, ret);
54224 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
54228 // GridPanel (grid, cfg)
54231 this.beginUpdate();
54235 Roo.each(xitems, function(i) {
54236 region = nb && i.region ? i.region : false;
54238 var add = ret.addxtype(i);
54241 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
54242 if (!i.background) {
54243 abn[region] = nb[region] ;
54250 // make the last non-background panel active..
54251 //if (nb) { Roo.log(abn); }
54254 for(var r in abn) {
54255 region = this.getRegion(r);
54257 // tried using nb[r], but it does not work..
54259 region.showPanel(abn[r]);
54270 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
54271 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
54272 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
54273 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
54276 var CP = Roo.ContentPanel;
54278 var layout = Roo.BorderLayout.create({
54282 panels: [new CP("north", "North")]
54291 panels: [new CP("west", {title: "West"})]
54300 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
54309 panels: [new CP("south", {title: "South", closable: true})]
54316 preferredTabWidth: 150,
54318 new CP("center1", {title: "Close Me", closable: true}),
54319 new CP("center2", {title: "Center Panel", closable: false})
54324 layout.getRegion("center").showPanel("center1");
54329 Roo.BorderLayout.create = function(config, targetEl){
54330 var layout = new Roo.BorderLayout(targetEl || document.body, config);
54331 layout.beginUpdate();
54332 var regions = Roo.BorderLayout.RegionFactory.validRegions;
54333 for(var j = 0, jlen = regions.length; j < jlen; j++){
54334 var lr = regions[j];
54335 if(layout.regions[lr] && config[lr].panels){
54336 var r = layout.regions[lr];
54337 var ps = config[lr].panels;
54338 layout.addTypedPanels(r, ps);
54341 layout.endUpdate();
54346 Roo.BorderLayout.RegionFactory = {
54348 validRegions : ["north","south","east","west","center"],
54351 create : function(target, mgr, config){
54352 target = target.toLowerCase();
54353 if(config.lightweight || config.basic){
54354 return new Roo.BasicLayoutRegion(mgr, config, target);
54358 return new Roo.NorthLayoutRegion(mgr, config);
54360 return new Roo.SouthLayoutRegion(mgr, config);
54362 return new Roo.EastLayoutRegion(mgr, config);
54364 return new Roo.WestLayoutRegion(mgr, config);
54366 return new Roo.CenterLayoutRegion(mgr, config);
54368 throw 'Layout region "'+target+'" not supported.';
54372 * Ext JS Library 1.1.1
54373 * Copyright(c) 2006-2007, Ext JS, LLC.
54375 * Originally Released Under LGPL - original licence link has changed is not relivant.
54378 * <script type="text/javascript">
54382 * @class Roo.BasicLayoutRegion
54383 * @extends Roo.util.Observable
54384 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
54385 * and does not have a titlebar, tabs or any other features. All it does is size and position
54386 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
54388 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
54390 this.position = pos;
54393 * @scope Roo.BasicLayoutRegion
54397 * @event beforeremove
54398 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
54399 * @param {Roo.LayoutRegion} this
54400 * @param {Roo.ContentPanel} panel The panel
54401 * @param {Object} e The cancel event object
54403 "beforeremove" : true,
54405 * @event invalidated
54406 * Fires when the layout for this region is changed.
54407 * @param {Roo.LayoutRegion} this
54409 "invalidated" : true,
54411 * @event visibilitychange
54412 * Fires when this region is shown or hidden
54413 * @param {Roo.LayoutRegion} this
54414 * @param {Boolean} visibility true or false
54416 "visibilitychange" : true,
54418 * @event paneladded
54419 * Fires when a panel is added.
54420 * @param {Roo.LayoutRegion} this
54421 * @param {Roo.ContentPanel} panel The panel
54423 "paneladded" : true,
54425 * @event panelremoved
54426 * Fires when a panel is removed.
54427 * @param {Roo.LayoutRegion} this
54428 * @param {Roo.ContentPanel} panel The panel
54430 "panelremoved" : true,
54432 * @event beforecollapse
54433 * Fires when this region before collapse.
54434 * @param {Roo.LayoutRegion} this
54436 "beforecollapse" : true,
54439 * Fires when this region is collapsed.
54440 * @param {Roo.LayoutRegion} this
54442 "collapsed" : true,
54445 * Fires when this region is expanded.
54446 * @param {Roo.LayoutRegion} this
54451 * Fires when this region is slid into view.
54452 * @param {Roo.LayoutRegion} this
54454 "slideshow" : true,
54457 * Fires when this region slides out of view.
54458 * @param {Roo.LayoutRegion} this
54460 "slidehide" : true,
54462 * @event panelactivated
54463 * Fires when a panel is activated.
54464 * @param {Roo.LayoutRegion} this
54465 * @param {Roo.ContentPanel} panel The activated panel
54467 "panelactivated" : true,
54470 * Fires when the user resizes this region.
54471 * @param {Roo.LayoutRegion} this
54472 * @param {Number} newSize The new size (width for east/west, height for north/south)
54476 /** A collection of panels in this region. @type Roo.util.MixedCollection */
54477 this.panels = new Roo.util.MixedCollection();
54478 this.panels.getKey = this.getPanelId.createDelegate(this);
54480 this.activePanel = null;
54481 // ensure listeners are added...
54483 if (config.listeners || config.events) {
54484 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
54485 listeners : config.listeners || {},
54486 events : config.events || {}
54490 if(skipConfig !== true){
54491 this.applyConfig(config);
54495 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
54496 getPanelId : function(p){
54500 applyConfig : function(config){
54501 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
54502 this.config = config;
54507 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
54508 * the width, for horizontal (north, south) the height.
54509 * @param {Number} newSize The new width or height
54511 resizeTo : function(newSize){
54512 var el = this.el ? this.el :
54513 (this.activePanel ? this.activePanel.getEl() : null);
54515 switch(this.position){
54518 el.setWidth(newSize);
54519 this.fireEvent("resized", this, newSize);
54523 el.setHeight(newSize);
54524 this.fireEvent("resized", this, newSize);
54530 getBox : function(){
54531 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
54534 getMargins : function(){
54535 return this.margins;
54538 updateBox : function(box){
54540 var el = this.activePanel.getEl();
54541 el.dom.style.left = box.x + "px";
54542 el.dom.style.top = box.y + "px";
54543 this.activePanel.setSize(box.width, box.height);
54547 * Returns the container element for this region.
54548 * @return {Roo.Element}
54550 getEl : function(){
54551 return this.activePanel;
54555 * Returns true if this region is currently visible.
54556 * @return {Boolean}
54558 isVisible : function(){
54559 return this.activePanel ? true : false;
54562 setActivePanel : function(panel){
54563 panel = this.getPanel(panel);
54564 if(this.activePanel && this.activePanel != panel){
54565 this.activePanel.setActiveState(false);
54566 this.activePanel.getEl().setLeftTop(-10000,-10000);
54568 this.activePanel = panel;
54569 panel.setActiveState(true);
54571 panel.setSize(this.box.width, this.box.height);
54573 this.fireEvent("panelactivated", this, panel);
54574 this.fireEvent("invalidated");
54578 * Show the specified panel.
54579 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
54580 * @return {Roo.ContentPanel} The shown panel or null
54582 showPanel : function(panel){
54583 if(panel = this.getPanel(panel)){
54584 this.setActivePanel(panel);
54590 * Get the active panel for this region.
54591 * @return {Roo.ContentPanel} The active panel or null
54593 getActivePanel : function(){
54594 return this.activePanel;
54598 * Add the passed ContentPanel(s)
54599 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
54600 * @return {Roo.ContentPanel} The panel added (if only one was added)
54602 add : function(panel){
54603 if(arguments.length > 1){
54604 for(var i = 0, len = arguments.length; i < len; i++) {
54605 this.add(arguments[i]);
54609 if(this.hasPanel(panel)){
54610 this.showPanel(panel);
54613 var el = panel.getEl();
54614 if(el.dom.parentNode != this.mgr.el.dom){
54615 this.mgr.el.dom.appendChild(el.dom);
54617 if(panel.setRegion){
54618 panel.setRegion(this);
54620 this.panels.add(panel);
54621 el.setStyle("position", "absolute");
54622 if(!panel.background){
54623 this.setActivePanel(panel);
54624 if(this.config.initialSize && this.panels.getCount()==1){
54625 this.resizeTo(this.config.initialSize);
54628 this.fireEvent("paneladded", this, panel);
54633 * Returns true if the panel is in this region.
54634 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
54635 * @return {Boolean}
54637 hasPanel : function(panel){
54638 if(typeof panel == "object"){ // must be panel obj
54639 panel = panel.getId();
54641 return this.getPanel(panel) ? true : false;
54645 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
54646 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
54647 * @param {Boolean} preservePanel Overrides the config preservePanel option
54648 * @return {Roo.ContentPanel} The panel that was removed
54650 remove : function(panel, preservePanel){
54651 panel = this.getPanel(panel);
54656 this.fireEvent("beforeremove", this, panel, e);
54657 if(e.cancel === true){
54660 var panelId = panel.getId();
54661 this.panels.removeKey(panelId);
54666 * Returns the panel specified or null if it's not in this region.
54667 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
54668 * @return {Roo.ContentPanel}
54670 getPanel : function(id){
54671 if(typeof id == "object"){ // must be panel obj
54674 return this.panels.get(id);
54678 * Returns this regions position (north/south/east/west/center).
54681 getPosition: function(){
54682 return this.position;
54686 * Ext JS Library 1.1.1
54687 * Copyright(c) 2006-2007, Ext JS, LLC.
54689 * Originally Released Under LGPL - original licence link has changed is not relivant.
54692 * <script type="text/javascript">
54696 * @class Roo.LayoutRegion
54697 * @extends Roo.BasicLayoutRegion
54698 * This class represents a region in a layout manager.
54699 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
54700 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
54701 * @cfg {Boolean} floatable False to disable floating (defaults to true)
54702 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
54703 * @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})
54704 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
54705 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
54706 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
54707 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
54708 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
54709 * @cfg {String} title The title for the region (overrides panel titles)
54710 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
54711 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
54712 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
54713 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
54714 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
54715 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
54716 * the space available, similar to FireFox 1.5 tabs (defaults to false)
54717 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
54718 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
54719 * @cfg {Boolean} showPin True to show a pin button
54720 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
54721 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
54722 * @cfg {Boolean} disableTabTips True to disable tab tooltips
54723 * @cfg {Number} width For East/West panels
54724 * @cfg {Number} height For North/South panels
54725 * @cfg {Boolean} split To show the splitter
54726 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
54728 Roo.LayoutRegion = function(mgr, config, pos){
54729 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
54730 var dh = Roo.DomHelper;
54731 /** This region's container element
54732 * @type Roo.Element */
54733 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
54734 /** This region's title element
54735 * @type Roo.Element */
54737 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
54738 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
54739 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
54741 this.titleEl.enableDisplayMode();
54742 /** This region's title text element
54743 * @type HTMLElement */
54744 this.titleTextEl = this.titleEl.dom.firstChild;
54745 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
54746 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
54747 this.closeBtn.enableDisplayMode();
54748 this.closeBtn.on("click", this.closeClicked, this);
54749 this.closeBtn.hide();
54751 this.createBody(config);
54752 this.visible = true;
54753 this.collapsed = false;
54755 if(config.hideWhenEmpty){
54757 this.on("paneladded", this.validateVisibility, this);
54758 this.on("panelremoved", this.validateVisibility, this);
54760 this.applyConfig(config);
54763 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
54765 createBody : function(){
54766 /** This region's body element
54767 * @type Roo.Element */
54768 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
54771 applyConfig : function(c){
54772 if(c.collapsible && this.position != "center" && !this.collapsedEl){
54773 var dh = Roo.DomHelper;
54774 if(c.titlebar !== false){
54775 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
54776 this.collapseBtn.on("click", this.collapse, this);
54777 this.collapseBtn.enableDisplayMode();
54779 if(c.showPin === true || this.showPin){
54780 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
54781 this.stickBtn.enableDisplayMode();
54782 this.stickBtn.on("click", this.expand, this);
54783 this.stickBtn.hide();
54786 /** This region's collapsed element
54787 * @type Roo.Element */
54788 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
54789 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
54791 if(c.floatable !== false){
54792 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
54793 this.collapsedEl.on("click", this.collapseClick, this);
54796 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
54797 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
54798 id: "message", unselectable: "on", style:{"float":"left"}});
54799 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
54801 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
54802 this.expandBtn.on("click", this.expand, this);
54804 if(this.collapseBtn){
54805 this.collapseBtn.setVisible(c.collapsible == true);
54807 this.cmargins = c.cmargins || this.cmargins ||
54808 (this.position == "west" || this.position == "east" ?
54809 {top: 0, left: 2, right:2, bottom: 0} :
54810 {top: 2, left: 0, right:0, bottom: 2});
54811 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
54812 this.bottomTabs = c.tabPosition != "top";
54813 this.autoScroll = c.autoScroll || false;
54814 if(this.autoScroll){
54815 this.bodyEl.setStyle("overflow", "auto");
54817 this.bodyEl.setStyle("overflow", "hidden");
54819 //if(c.titlebar !== false){
54820 if((!c.titlebar && !c.title) || c.titlebar === false){
54821 this.titleEl.hide();
54823 this.titleEl.show();
54825 this.titleTextEl.innerHTML = c.title;
54829 this.duration = c.duration || .30;
54830 this.slideDuration = c.slideDuration || .45;
54833 this.collapse(true);
54840 * Returns true if this region is currently visible.
54841 * @return {Boolean}
54843 isVisible : function(){
54844 return this.visible;
54848 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
54849 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
54851 setCollapsedTitle : function(title){
54852 title = title || " ";
54853 if(this.collapsedTitleTextEl){
54854 this.collapsedTitleTextEl.innerHTML = title;
54858 getBox : function(){
54860 if(!this.collapsed){
54861 b = this.el.getBox(false, true);
54863 b = this.collapsedEl.getBox(false, true);
54868 getMargins : function(){
54869 return this.collapsed ? this.cmargins : this.margins;
54872 highlight : function(){
54873 this.el.addClass("x-layout-panel-dragover");
54876 unhighlight : function(){
54877 this.el.removeClass("x-layout-panel-dragover");
54880 updateBox : function(box){
54882 if(!this.collapsed){
54883 this.el.dom.style.left = box.x + "px";
54884 this.el.dom.style.top = box.y + "px";
54885 this.updateBody(box.width, box.height);
54887 this.collapsedEl.dom.style.left = box.x + "px";
54888 this.collapsedEl.dom.style.top = box.y + "px";
54889 this.collapsedEl.setSize(box.width, box.height);
54892 this.tabs.autoSizeTabs();
54896 updateBody : function(w, h){
54898 this.el.setWidth(w);
54899 w -= this.el.getBorderWidth("rl");
54900 if(this.config.adjustments){
54901 w += this.config.adjustments[0];
54905 this.el.setHeight(h);
54906 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
54907 h -= this.el.getBorderWidth("tb");
54908 if(this.config.adjustments){
54909 h += this.config.adjustments[1];
54911 this.bodyEl.setHeight(h);
54913 h = this.tabs.syncHeight(h);
54916 if(this.panelSize){
54917 w = w !== null ? w : this.panelSize.width;
54918 h = h !== null ? h : this.panelSize.height;
54920 if(this.activePanel){
54921 var el = this.activePanel.getEl();
54922 w = w !== null ? w : el.getWidth();
54923 h = h !== null ? h : el.getHeight();
54924 this.panelSize = {width: w, height: h};
54925 this.activePanel.setSize(w, h);
54927 if(Roo.isIE && this.tabs){
54928 this.tabs.el.repaint();
54933 * Returns the container element for this region.
54934 * @return {Roo.Element}
54936 getEl : function(){
54941 * Hides this region.
54944 if(!this.collapsed){
54945 this.el.dom.style.left = "-2000px";
54948 this.collapsedEl.dom.style.left = "-2000px";
54949 this.collapsedEl.hide();
54951 this.visible = false;
54952 this.fireEvent("visibilitychange", this, false);
54956 * Shows this region if it was previously hidden.
54959 if(!this.collapsed){
54962 this.collapsedEl.show();
54964 this.visible = true;
54965 this.fireEvent("visibilitychange", this, true);
54968 closeClicked : function(){
54969 if(this.activePanel){
54970 this.remove(this.activePanel);
54974 collapseClick : function(e){
54976 e.stopPropagation();
54979 e.stopPropagation();
54985 * Collapses this region.
54986 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
54988 collapse : function(skipAnim, skipCheck){
54989 if(this.collapsed) {
54993 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
54995 this.collapsed = true;
54997 this.split.el.hide();
54999 if(this.config.animate && skipAnim !== true){
55000 this.fireEvent("invalidated", this);
55001 this.animateCollapse();
55003 this.el.setLocation(-20000,-20000);
55005 this.collapsedEl.show();
55006 this.fireEvent("collapsed", this);
55007 this.fireEvent("invalidated", this);
55013 animateCollapse : function(){
55018 * Expands this region if it was previously collapsed.
55019 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
55020 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
55022 expand : function(e, skipAnim){
55024 e.stopPropagation();
55026 if(!this.collapsed || this.el.hasActiveFx()) {
55030 this.afterSlideIn();
55033 this.collapsed = false;
55034 if(this.config.animate && skipAnim !== true){
55035 this.animateExpand();
55039 this.split.el.show();
55041 this.collapsedEl.setLocation(-2000,-2000);
55042 this.collapsedEl.hide();
55043 this.fireEvent("invalidated", this);
55044 this.fireEvent("expanded", this);
55048 animateExpand : function(){
55052 initTabs : function()
55054 this.bodyEl.setStyle("overflow", "hidden");
55055 var ts = new Roo.TabPanel(
55058 tabPosition: this.bottomTabs ? 'bottom' : 'top',
55059 disableTooltips: this.config.disableTabTips,
55060 toolbar : this.config.toolbar
55063 if(this.config.hideTabs){
55064 ts.stripWrap.setDisplayed(false);
55067 ts.resizeTabs = this.config.resizeTabs === true;
55068 ts.minTabWidth = this.config.minTabWidth || 40;
55069 ts.maxTabWidth = this.config.maxTabWidth || 250;
55070 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
55071 ts.monitorResize = false;
55072 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
55073 ts.bodyEl.addClass('x-layout-tabs-body');
55074 this.panels.each(this.initPanelAsTab, this);
55077 initPanelAsTab : function(panel){
55078 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
55079 this.config.closeOnTab && panel.isClosable());
55080 if(panel.tabTip !== undefined){
55081 ti.setTooltip(panel.tabTip);
55083 ti.on("activate", function(){
55084 this.setActivePanel(panel);
55086 if(this.config.closeOnTab){
55087 ti.on("beforeclose", function(t, e){
55089 this.remove(panel);
55095 updatePanelTitle : function(panel, title){
55096 if(this.activePanel == panel){
55097 this.updateTitle(title);
55100 var ti = this.tabs.getTab(panel.getEl().id);
55102 if(panel.tabTip !== undefined){
55103 ti.setTooltip(panel.tabTip);
55108 updateTitle : function(title){
55109 if(this.titleTextEl && !this.config.title){
55110 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
55114 setActivePanel : function(panel){
55115 panel = this.getPanel(panel);
55116 if(this.activePanel && this.activePanel != panel){
55117 this.activePanel.setActiveState(false);
55119 this.activePanel = panel;
55120 panel.setActiveState(true);
55121 if(this.panelSize){
55122 panel.setSize(this.panelSize.width, this.panelSize.height);
55125 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
55127 this.updateTitle(panel.getTitle());
55129 this.fireEvent("invalidated", this);
55131 this.fireEvent("panelactivated", this, panel);
55135 * Shows the specified panel.
55136 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
55137 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
55139 showPanel : function(panel)
55141 panel = this.getPanel(panel);
55144 var tab = this.tabs.getTab(panel.getEl().id);
55145 if(tab.isHidden()){
55146 this.tabs.unhideTab(tab.id);
55150 this.setActivePanel(panel);
55157 * Get the active panel for this region.
55158 * @return {Roo.ContentPanel} The active panel or null
55160 getActivePanel : function(){
55161 return this.activePanel;
55164 validateVisibility : function(){
55165 if(this.panels.getCount() < 1){
55166 this.updateTitle(" ");
55167 this.closeBtn.hide();
55170 if(!this.isVisible()){
55177 * Adds the passed ContentPanel(s) to this region.
55178 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
55179 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
55181 add : function(panel){
55182 if(arguments.length > 1){
55183 for(var i = 0, len = arguments.length; i < len; i++) {
55184 this.add(arguments[i]);
55188 if(this.hasPanel(panel)){
55189 this.showPanel(panel);
55192 panel.setRegion(this);
55193 this.panels.add(panel);
55194 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
55195 this.bodyEl.dom.appendChild(panel.getEl().dom);
55196 if(panel.background !== true){
55197 this.setActivePanel(panel);
55199 this.fireEvent("paneladded", this, panel);
55205 this.initPanelAsTab(panel);
55207 if(panel.background !== true){
55208 this.tabs.activate(panel.getEl().id);
55210 this.fireEvent("paneladded", this, panel);
55215 * Hides the tab for the specified panel.
55216 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
55218 hidePanel : function(panel){
55219 if(this.tabs && (panel = this.getPanel(panel))){
55220 this.tabs.hideTab(panel.getEl().id);
55225 * Unhides the tab for a previously hidden panel.
55226 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
55228 unhidePanel : function(panel){
55229 if(this.tabs && (panel = this.getPanel(panel))){
55230 this.tabs.unhideTab(panel.getEl().id);
55234 clearPanels : function(){
55235 while(this.panels.getCount() > 0){
55236 this.remove(this.panels.first());
55241 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
55242 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
55243 * @param {Boolean} preservePanel Overrides the config preservePanel option
55244 * @return {Roo.ContentPanel} The panel that was removed
55246 remove : function(panel, preservePanel){
55247 panel = this.getPanel(panel);
55252 this.fireEvent("beforeremove", this, panel, e);
55253 if(e.cancel === true){
55256 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
55257 var panelId = panel.getId();
55258 this.panels.removeKey(panelId);
55260 document.body.appendChild(panel.getEl().dom);
55263 this.tabs.removeTab(panel.getEl().id);
55264 }else if (!preservePanel){
55265 this.bodyEl.dom.removeChild(panel.getEl().dom);
55267 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
55268 var p = this.panels.first();
55269 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
55270 tempEl.appendChild(p.getEl().dom);
55271 this.bodyEl.update("");
55272 this.bodyEl.dom.appendChild(p.getEl().dom);
55274 this.updateTitle(p.getTitle());
55276 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
55277 this.setActivePanel(p);
55279 panel.setRegion(null);
55280 if(this.activePanel == panel){
55281 this.activePanel = null;
55283 if(this.config.autoDestroy !== false && preservePanel !== true){
55284 try{panel.destroy();}catch(e){}
55286 this.fireEvent("panelremoved", this, panel);
55291 * Returns the TabPanel component used by this region
55292 * @return {Roo.TabPanel}
55294 getTabs : function(){
55298 createTool : function(parentEl, className){
55299 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
55300 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
55301 btn.addClassOnOver("x-layout-tools-button-over");
55306 * Ext JS Library 1.1.1
55307 * Copyright(c) 2006-2007, Ext JS, LLC.
55309 * Originally Released Under LGPL - original licence link has changed is not relivant.
55312 * <script type="text/javascript">
55318 * @class Roo.SplitLayoutRegion
55319 * @extends Roo.LayoutRegion
55320 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
55322 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
55323 this.cursor = cursor;
55324 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
55327 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
55328 splitTip : "Drag to resize.",
55329 collapsibleSplitTip : "Drag to resize. Double click to hide.",
55330 useSplitTips : false,
55332 applyConfig : function(config){
55333 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
55336 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
55337 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
55338 /** The SplitBar for this region
55339 * @type Roo.SplitBar */
55340 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
55341 this.split.on("moved", this.onSplitMove, this);
55342 this.split.useShim = config.useShim === true;
55343 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
55344 if(this.useSplitTips){
55345 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
55347 if(config.collapsible){
55348 this.split.el.on("dblclick", this.collapse, this);
55351 if(typeof config.minSize != "undefined"){
55352 this.split.minSize = config.minSize;
55354 if(typeof config.maxSize != "undefined"){
55355 this.split.maxSize = config.maxSize;
55357 if(config.hideWhenEmpty || config.hidden || config.collapsed){
55358 this.hideSplitter();
55363 getHMaxSize : function(){
55364 var cmax = this.config.maxSize || 10000;
55365 var center = this.mgr.getRegion("center");
55366 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
55369 getVMaxSize : function(){
55370 var cmax = this.config.maxSize || 10000;
55371 var center = this.mgr.getRegion("center");
55372 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
55375 onSplitMove : function(split, newSize){
55376 this.fireEvent("resized", this, newSize);
55380 * Returns the {@link Roo.SplitBar} for this region.
55381 * @return {Roo.SplitBar}
55383 getSplitBar : function(){
55388 this.hideSplitter();
55389 Roo.SplitLayoutRegion.superclass.hide.call(this);
55392 hideSplitter : function(){
55394 this.split.el.setLocation(-2000,-2000);
55395 this.split.el.hide();
55401 this.split.el.show();
55403 Roo.SplitLayoutRegion.superclass.show.call(this);
55406 beforeSlide: function(){
55407 if(Roo.isGecko){// firefox overflow auto bug workaround
55408 this.bodyEl.clip();
55410 this.tabs.bodyEl.clip();
55412 if(this.activePanel){
55413 this.activePanel.getEl().clip();
55415 if(this.activePanel.beforeSlide){
55416 this.activePanel.beforeSlide();
55422 afterSlide : function(){
55423 if(Roo.isGecko){// firefox overflow auto bug workaround
55424 this.bodyEl.unclip();
55426 this.tabs.bodyEl.unclip();
55428 if(this.activePanel){
55429 this.activePanel.getEl().unclip();
55430 if(this.activePanel.afterSlide){
55431 this.activePanel.afterSlide();
55437 initAutoHide : function(){
55438 if(this.autoHide !== false){
55439 if(!this.autoHideHd){
55440 var st = new Roo.util.DelayedTask(this.slideIn, this);
55441 this.autoHideHd = {
55442 "mouseout": function(e){
55443 if(!e.within(this.el, true)){
55447 "mouseover" : function(e){
55453 this.el.on(this.autoHideHd);
55457 clearAutoHide : function(){
55458 if(this.autoHide !== false){
55459 this.el.un("mouseout", this.autoHideHd.mouseout);
55460 this.el.un("mouseover", this.autoHideHd.mouseover);
55464 clearMonitor : function(){
55465 Roo.get(document).un("click", this.slideInIf, this);
55468 // these names are backwards but not changed for compat
55469 slideOut : function(){
55470 if(this.isSlid || this.el.hasActiveFx()){
55473 this.isSlid = true;
55474 if(this.collapseBtn){
55475 this.collapseBtn.hide();
55477 this.closeBtnState = this.closeBtn.getStyle('display');
55478 this.closeBtn.hide();
55480 this.stickBtn.show();
55483 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
55484 this.beforeSlide();
55485 this.el.setStyle("z-index", 10001);
55486 this.el.slideIn(this.getSlideAnchor(), {
55487 callback: function(){
55489 this.initAutoHide();
55490 Roo.get(document).on("click", this.slideInIf, this);
55491 this.fireEvent("slideshow", this);
55498 afterSlideIn : function(){
55499 this.clearAutoHide();
55500 this.isSlid = false;
55501 this.clearMonitor();
55502 this.el.setStyle("z-index", "");
55503 if(this.collapseBtn){
55504 this.collapseBtn.show();
55506 this.closeBtn.setStyle('display', this.closeBtnState);
55508 this.stickBtn.hide();
55510 this.fireEvent("slidehide", this);
55513 slideIn : function(cb){
55514 if(!this.isSlid || this.el.hasActiveFx()){
55518 this.isSlid = false;
55519 this.beforeSlide();
55520 this.el.slideOut(this.getSlideAnchor(), {
55521 callback: function(){
55522 this.el.setLeftTop(-10000, -10000);
55524 this.afterSlideIn();
55532 slideInIf : function(e){
55533 if(!e.within(this.el)){
55538 animateCollapse : function(){
55539 this.beforeSlide();
55540 this.el.setStyle("z-index", 20000);
55541 var anchor = this.getSlideAnchor();
55542 this.el.slideOut(anchor, {
55543 callback : function(){
55544 this.el.setStyle("z-index", "");
55545 this.collapsedEl.slideIn(anchor, {duration:.3});
55547 this.el.setLocation(-10000,-10000);
55549 this.fireEvent("collapsed", this);
55556 animateExpand : function(){
55557 this.beforeSlide();
55558 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
55559 this.el.setStyle("z-index", 20000);
55560 this.collapsedEl.hide({
55563 this.el.slideIn(this.getSlideAnchor(), {
55564 callback : function(){
55565 this.el.setStyle("z-index", "");
55568 this.split.el.show();
55570 this.fireEvent("invalidated", this);
55571 this.fireEvent("expanded", this);
55599 getAnchor : function(){
55600 return this.anchors[this.position];
55603 getCollapseAnchor : function(){
55604 return this.canchors[this.position];
55607 getSlideAnchor : function(){
55608 return this.sanchors[this.position];
55611 getAlignAdj : function(){
55612 var cm = this.cmargins;
55613 switch(this.position){
55629 getExpandAdj : function(){
55630 var c = this.collapsedEl, cm = this.cmargins;
55631 switch(this.position){
55633 return [-(cm.right+c.getWidth()+cm.left), 0];
55636 return [cm.right+c.getWidth()+cm.left, 0];
55639 return [0, -(cm.top+cm.bottom+c.getHeight())];
55642 return [0, cm.top+cm.bottom+c.getHeight()];
55648 * Ext JS Library 1.1.1
55649 * Copyright(c) 2006-2007, Ext JS, LLC.
55651 * Originally Released Under LGPL - original licence link has changed is not relivant.
55654 * <script type="text/javascript">
55657 * These classes are private internal classes
55659 Roo.CenterLayoutRegion = function(mgr, config){
55660 Roo.LayoutRegion.call(this, mgr, config, "center");
55661 this.visible = true;
55662 this.minWidth = config.minWidth || 20;
55663 this.minHeight = config.minHeight || 20;
55666 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
55668 // center panel can't be hidden
55672 // center panel can't be hidden
55675 getMinWidth: function(){
55676 return this.minWidth;
55679 getMinHeight: function(){
55680 return this.minHeight;
55685 Roo.NorthLayoutRegion = function(mgr, config){
55686 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
55688 this.split.placement = Roo.SplitBar.TOP;
55689 this.split.orientation = Roo.SplitBar.VERTICAL;
55690 this.split.el.addClass("x-layout-split-v");
55692 var size = config.initialSize || config.height;
55693 if(typeof size != "undefined"){
55694 this.el.setHeight(size);
55697 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
55698 orientation: Roo.SplitBar.VERTICAL,
55699 getBox : function(){
55700 if(this.collapsed){
55701 return this.collapsedEl.getBox();
55703 var box = this.el.getBox();
55705 box.height += this.split.el.getHeight();
55710 updateBox : function(box){
55711 if(this.split && !this.collapsed){
55712 box.height -= this.split.el.getHeight();
55713 this.split.el.setLeft(box.x);
55714 this.split.el.setTop(box.y+box.height);
55715 this.split.el.setWidth(box.width);
55717 if(this.collapsed){
55718 this.updateBody(box.width, null);
55720 Roo.LayoutRegion.prototype.updateBox.call(this, box);
55724 Roo.SouthLayoutRegion = function(mgr, config){
55725 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
55727 this.split.placement = Roo.SplitBar.BOTTOM;
55728 this.split.orientation = Roo.SplitBar.VERTICAL;
55729 this.split.el.addClass("x-layout-split-v");
55731 var size = config.initialSize || config.height;
55732 if(typeof size != "undefined"){
55733 this.el.setHeight(size);
55736 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
55737 orientation: Roo.SplitBar.VERTICAL,
55738 getBox : function(){
55739 if(this.collapsed){
55740 return this.collapsedEl.getBox();
55742 var box = this.el.getBox();
55744 var sh = this.split.el.getHeight();
55751 updateBox : function(box){
55752 if(this.split && !this.collapsed){
55753 var sh = this.split.el.getHeight();
55756 this.split.el.setLeft(box.x);
55757 this.split.el.setTop(box.y-sh);
55758 this.split.el.setWidth(box.width);
55760 if(this.collapsed){
55761 this.updateBody(box.width, null);
55763 Roo.LayoutRegion.prototype.updateBox.call(this, box);
55767 Roo.EastLayoutRegion = function(mgr, config){
55768 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
55770 this.split.placement = Roo.SplitBar.RIGHT;
55771 this.split.orientation = Roo.SplitBar.HORIZONTAL;
55772 this.split.el.addClass("x-layout-split-h");
55774 var size = config.initialSize || config.width;
55775 if(typeof size != "undefined"){
55776 this.el.setWidth(size);
55779 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
55780 orientation: Roo.SplitBar.HORIZONTAL,
55781 getBox : function(){
55782 if(this.collapsed){
55783 return this.collapsedEl.getBox();
55785 var box = this.el.getBox();
55787 var sw = this.split.el.getWidth();
55794 updateBox : function(box){
55795 if(this.split && !this.collapsed){
55796 var sw = this.split.el.getWidth();
55798 this.split.el.setLeft(box.x);
55799 this.split.el.setTop(box.y);
55800 this.split.el.setHeight(box.height);
55803 if(this.collapsed){
55804 this.updateBody(null, box.height);
55806 Roo.LayoutRegion.prototype.updateBox.call(this, box);
55810 Roo.WestLayoutRegion = function(mgr, config){
55811 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
55813 this.split.placement = Roo.SplitBar.LEFT;
55814 this.split.orientation = Roo.SplitBar.HORIZONTAL;
55815 this.split.el.addClass("x-layout-split-h");
55817 var size = config.initialSize || config.width;
55818 if(typeof size != "undefined"){
55819 this.el.setWidth(size);
55822 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
55823 orientation: Roo.SplitBar.HORIZONTAL,
55824 getBox : function(){
55825 if(this.collapsed){
55826 return this.collapsedEl.getBox();
55828 var box = this.el.getBox();
55830 box.width += this.split.el.getWidth();
55835 updateBox : function(box){
55836 if(this.split && !this.collapsed){
55837 var sw = this.split.el.getWidth();
55839 this.split.el.setLeft(box.x+box.width);
55840 this.split.el.setTop(box.y);
55841 this.split.el.setHeight(box.height);
55843 if(this.collapsed){
55844 this.updateBody(null, box.height);
55846 Roo.LayoutRegion.prototype.updateBox.call(this, box);
55851 * Ext JS Library 1.1.1
55852 * Copyright(c) 2006-2007, Ext JS, LLC.
55854 * Originally Released Under LGPL - original licence link has changed is not relivant.
55857 * <script type="text/javascript">
55862 * Private internal class for reading and applying state
55864 Roo.LayoutStateManager = function(layout){
55865 // default empty state
55874 Roo.LayoutStateManager.prototype = {
55875 init : function(layout, provider){
55876 this.provider = provider;
55877 var state = provider.get(layout.id+"-layout-state");
55879 var wasUpdating = layout.isUpdating();
55881 layout.beginUpdate();
55883 for(var key in state){
55884 if(typeof state[key] != "function"){
55885 var rstate = state[key];
55886 var r = layout.getRegion(key);
55889 r.resizeTo(rstate.size);
55891 if(rstate.collapsed == true){
55894 r.expand(null, true);
55900 layout.endUpdate();
55902 this.state = state;
55904 this.layout = layout;
55905 layout.on("regionresized", this.onRegionResized, this);
55906 layout.on("regioncollapsed", this.onRegionCollapsed, this);
55907 layout.on("regionexpanded", this.onRegionExpanded, this);
55910 storeState : function(){
55911 this.provider.set(this.layout.id+"-layout-state", this.state);
55914 onRegionResized : function(region, newSize){
55915 this.state[region.getPosition()].size = newSize;
55919 onRegionCollapsed : function(region){
55920 this.state[region.getPosition()].collapsed = true;
55924 onRegionExpanded : function(region){
55925 this.state[region.getPosition()].collapsed = false;
55930 * Ext JS Library 1.1.1
55931 * Copyright(c) 2006-2007, Ext JS, LLC.
55933 * Originally Released Under LGPL - original licence link has changed is not relivant.
55936 * <script type="text/javascript">
55939 * @class Roo.ContentPanel
55940 * @extends Roo.util.Observable
55941 * @children Roo.form.Form Roo.JsonView Roo.View
55942 * @parent Roo.BorderLayout Roo.LayoutDialog builder-top
55943 * A basic ContentPanel element.
55944 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
55945 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
55946 * @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
55947 * @cfg {Boolean} closable True if the panel can be closed/removed
55948 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
55949 * @cfg {String|HTMLElement|Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
55950 * @cfg {Roo.Toolbar} toolbar A toolbar for this panel
55951 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
55952 * @cfg {String} title The title for this panel
55953 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
55954 * @cfg {String} url Calls {@link #setUrl} with this value
55955 * @cfg {String} region [required] (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
55956 * @cfg {String|Object} params When used with {@link #url}, calls {@link #setUrl} with this value
55957 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
55958 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
55959 * @cfg {String} style Extra style to add to the content panel
55960 * @cfg {Roo.menu.Menu} menu popup menu
55963 * Create a new ContentPanel.
55964 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
55965 * @param {String/Object} config A string to set only the title or a config object
55966 * @param {String} content (optional) Set the HTML content for this panel
55967 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
55969 Roo.ContentPanel = function(el, config, content){
55973 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
55977 if (config && config.parentLayout) {
55978 el = config.parentLayout.el.createChild();
55981 if(el.autoCreate){ // xtype is available if this is called from factory
55985 this.el = Roo.get(el);
55986 if(!this.el && config && config.autoCreate){
55987 if(typeof config.autoCreate == "object"){
55988 if(!config.autoCreate.id){
55989 config.autoCreate.id = config.id||el;
55991 this.el = Roo.DomHelper.append(document.body,
55992 config.autoCreate, true);
55994 this.el = Roo.DomHelper.append(document.body,
55995 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
56000 this.closable = false;
56001 this.loaded = false;
56002 this.active = false;
56003 if(typeof config == "string"){
56004 this.title = config;
56006 Roo.apply(this, config);
56009 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
56010 this.wrapEl = this.el.wrap();
56011 this.toolbar.container = this.el.insertSibling(false, 'before');
56012 this.toolbar = new Roo.Toolbar(this.toolbar);
56015 // xtype created footer. - not sure if will work as we normally have to render first..
56016 if (this.footer && !this.footer.el && this.footer.xtype) {
56017 if (!this.wrapEl) {
56018 this.wrapEl = this.el.wrap();
56021 this.footer.container = this.wrapEl.createChild();
56023 this.footer = Roo.factory(this.footer, Roo);
56028 this.resizeEl = Roo.get(this.resizeEl, true);
56030 this.resizeEl = this.el;
56032 // handle view.xtype
56040 * Fires when this panel is activated.
56041 * @param {Roo.ContentPanel} this
56045 * @event deactivate
56046 * Fires when this panel is activated.
56047 * @param {Roo.ContentPanel} this
56049 "deactivate" : true,
56053 * Fires when this panel is resized if fitToFrame is true.
56054 * @param {Roo.ContentPanel} this
56055 * @param {Number} width The width after any component adjustments
56056 * @param {Number} height The height after any component adjustments
56062 * Fires when this tab is created
56063 * @param {Roo.ContentPanel} this
56073 if(this.autoScroll){
56074 this.resizeEl.setStyle("overflow", "auto");
56076 // fix randome scrolling
56077 this.el.on('scroll', function() {
56078 Roo.log('fix random scolling');
56079 this.scrollTo('top',0);
56082 content = content || this.content;
56084 this.setContent(content);
56086 if(config && config.url){
56087 this.setUrl(this.url, this.params, this.loadOnce);
56092 Roo.ContentPanel.superclass.constructor.call(this);
56094 if (this.view && typeof(this.view.xtype) != 'undefined') {
56095 this.view.el = this.el.appendChild(document.createElement("div"));
56096 this.view = Roo.factory(this.view);
56097 this.view.render && this.view.render(false, '');
56101 this.fireEvent('render', this);
56104 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
56106 setRegion : function(region){
56107 this.region = region;
56109 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
56111 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
56116 * Returns the toolbar for this Panel if one was configured.
56117 * @return {Roo.Toolbar}
56119 getToolbar : function(){
56120 return this.toolbar;
56123 setActiveState : function(active){
56124 this.active = active;
56126 this.fireEvent("deactivate", this);
56128 this.fireEvent("activate", this);
56132 * Updates this panel's element
56133 * @param {String} content The new content
56134 * @param {Boolean} loadScripts (optional) true to look for and process scripts
56136 setContent : function(content, loadScripts){
56137 this.el.update(content, loadScripts);
56140 ignoreResize : function(w, h){
56141 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
56144 this.lastSize = {width: w, height: h};
56149 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
56150 * @return {Roo.UpdateManager} The UpdateManager
56152 getUpdateManager : function(){
56153 return this.el.getUpdateManager();
56156 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
56157 * @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:
56160 url: "your-url.php",
56161 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
56162 callback: yourFunction,
56163 scope: yourObject, //(optional scope)
56166 text: "Loading...",
56171 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
56172 * 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.
56173 * @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}
56174 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
56175 * @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.
56176 * @return {Roo.ContentPanel} this
56179 var um = this.el.getUpdateManager();
56180 um.update.apply(um, arguments);
56186 * 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.
56187 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
56188 * @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)
56189 * @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)
56190 * @return {Roo.UpdateManager} The UpdateManager
56192 setUrl : function(url, params, loadOnce){
56193 if(this.refreshDelegate){
56194 this.removeListener("activate", this.refreshDelegate);
56196 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
56197 this.on("activate", this.refreshDelegate);
56198 return this.el.getUpdateManager();
56201 _handleRefresh : function(url, params, loadOnce){
56202 if(!loadOnce || !this.loaded){
56203 var updater = this.el.getUpdateManager();
56204 updater.update(url, params, this._setLoaded.createDelegate(this));
56208 _setLoaded : function(){
56209 this.loaded = true;
56213 * Returns this panel's id
56216 getId : function(){
56221 * Returns this panel's element - used by regiosn to add.
56222 * @return {Roo.Element}
56224 getEl : function(){
56225 return this.wrapEl || this.el;
56228 adjustForComponents : function(width, height)
56230 //Roo.log('adjustForComponents ');
56231 if(this.resizeEl != this.el){
56232 width -= this.el.getFrameWidth('lr');
56233 height -= this.el.getFrameWidth('tb');
56236 var te = this.toolbar.getEl();
56237 height -= te.getHeight();
56238 te.setWidth(width);
56241 var te = this.footer.getEl();
56242 //Roo.log("footer:" + te.getHeight());
56244 height -= te.getHeight();
56245 te.setWidth(width);
56249 if(this.adjustments){
56250 width += this.adjustments[0];
56251 height += this.adjustments[1];
56253 return {"width": width, "height": height};
56256 setSize : function(width, height){
56257 if(this.fitToFrame && !this.ignoreResize(width, height)){
56258 if(this.fitContainer && this.resizeEl != this.el){
56259 this.el.setSize(width, height);
56261 var size = this.adjustForComponents(width, height);
56262 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
56263 this.fireEvent('resize', this, size.width, size.height);
56268 * Returns this panel's title
56271 getTitle : function(){
56276 * Set this panel's title
56277 * @param {String} title
56279 setTitle : function(title){
56280 this.title = title;
56282 this.region.updatePanelTitle(this, title);
56287 * Returns true is this panel was configured to be closable
56288 * @return {Boolean}
56290 isClosable : function(){
56291 return this.closable;
56294 beforeSlide : function(){
56296 this.resizeEl.clip();
56299 afterSlide : function(){
56301 this.resizeEl.unclip();
56305 * Force a content refresh from the URL specified in the {@link #setUrl} method.
56306 * Will fail silently if the {@link #setUrl} method has not been called.
56307 * This does not activate the panel, just updates its content.
56309 refresh : function(){
56310 if(this.refreshDelegate){
56311 this.loaded = false;
56312 this.refreshDelegate();
56317 * Destroys this panel
56319 destroy : function(){
56320 this.el.removeAllListeners();
56321 var tempEl = document.createElement("span");
56322 tempEl.appendChild(this.el.dom);
56323 tempEl.innerHTML = "";
56329 * form - if the content panel contains a form - this is a reference to it.
56330 * @type {Roo.form.Form}
56334 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
56335 * This contains a reference to it.
56341 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
56351 * @param {Object} cfg Xtype definition of item to add.
56354 addxtype : function(cfg) {
56356 if (cfg.xtype.match(/^Form$/)) {
56359 //if (this.footer) {
56360 // el = this.footer.container.insertSibling(false, 'before');
56362 el = this.el.createChild();
56365 this.form = new Roo.form.Form(cfg);
56368 if ( this.form.allItems.length) {
56369 this.form.render(el.dom);
56373 // should only have one of theses..
56374 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
56375 // views.. should not be just added - used named prop 'view''
56377 cfg.el = this.el.appendChild(document.createElement("div"));
56380 var ret = new Roo.factory(cfg);
56382 ret.render && ret.render(false, ''); // render blank..
56391 * @class Roo.GridPanel
56392 * @extends Roo.ContentPanel
56394 * Create a new GridPanel.
56395 * @param {Roo.grid.Grid} grid The grid for this panel
56396 * @param {String/Object} config A string to set only the panel's title, or a config object
56398 Roo.GridPanel = function(grid, config){
56401 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
56402 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
56404 this.wrapper.dom.appendChild(grid.getGridEl().dom);
56406 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
56409 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
56411 // xtype created footer. - not sure if will work as we normally have to render first..
56412 if (this.footer && !this.footer.el && this.footer.xtype) {
56414 this.footer.container = this.grid.getView().getFooterPanel(true);
56415 this.footer.dataSource = this.grid.dataSource;
56416 this.footer = Roo.factory(this.footer, Roo);
56420 grid.monitorWindowResize = false; // turn off autosizing
56421 grid.autoHeight = false;
56422 grid.autoWidth = false;
56424 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
56427 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
56428 getId : function(){
56429 return this.grid.id;
56433 * Returns the grid for this panel
56434 * @return {Roo.grid.Grid}
56436 getGrid : function(){
56440 setSize : function(width, height){
56441 if(!this.ignoreResize(width, height)){
56442 var grid = this.grid;
56443 var size = this.adjustForComponents(width, height);
56444 grid.getGridEl().setSize(size.width, size.height);
56449 beforeSlide : function(){
56450 this.grid.getView().scroller.clip();
56453 afterSlide : function(){
56454 this.grid.getView().scroller.unclip();
56457 destroy : function(){
56458 this.grid.destroy();
56460 Roo.GridPanel.superclass.destroy.call(this);
56466 * @class Roo.NestedLayoutPanel
56467 * @extends Roo.ContentPanel
56469 * Create a new NestedLayoutPanel.
56472 * @param {Roo.BorderLayout} layout [required] The layout for this panel
56473 * @param {String/Object} config A string to set only the title or a config object
56475 Roo.NestedLayoutPanel = function(layout, config)
56477 // construct with only one argument..
56478 /* FIXME - implement nicer consturctors
56479 if (layout.layout) {
56481 layout = config.layout;
56482 delete config.layout;
56484 if (layout.xtype && !layout.getEl) {
56485 // then layout needs constructing..
56486 layout = Roo.factory(layout, Roo);
56491 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
56493 layout.monitorWindowResize = false; // turn off autosizing
56494 this.layout = layout;
56495 this.layout.getEl().addClass("x-layout-nested-layout");
56502 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
56504 setSize : function(width, height){
56505 if(!this.ignoreResize(width, height)){
56506 var size = this.adjustForComponents(width, height);
56507 var el = this.layout.getEl();
56508 el.setSize(size.width, size.height);
56509 var touch = el.dom.offsetWidth;
56510 this.layout.layout();
56511 // ie requires a double layout on the first pass
56512 if(Roo.isIE && !this.initialized){
56513 this.initialized = true;
56514 this.layout.layout();
56519 // activate all subpanels if not currently active..
56521 setActiveState : function(active){
56522 this.active = active;
56524 this.fireEvent("deactivate", this);
56528 this.fireEvent("activate", this);
56529 // not sure if this should happen before or after..
56530 if (!this.layout) {
56531 return; // should not happen..
56534 for (var r in this.layout.regions) {
56535 reg = this.layout.getRegion(r);
56536 if (reg.getActivePanel()) {
56537 //reg.showPanel(reg.getActivePanel()); // force it to activate..
56538 reg.setActivePanel(reg.getActivePanel());
56541 if (!reg.panels.length) {
56544 reg.showPanel(reg.getPanel(0));
56553 * Returns the nested BorderLayout for this panel
56554 * @return {Roo.BorderLayout}
56556 getLayout : function(){
56557 return this.layout;
56561 * Adds a xtype elements to the layout of the nested panel
56565 xtype : 'ContentPanel',
56572 xtype : 'NestedLayoutPanel',
56578 items : [ ... list of content panels or nested layout panels.. ]
56582 * @param {Object} cfg Xtype definition of item to add.
56584 addxtype : function(cfg) {
56585 return this.layout.addxtype(cfg);
56590 Roo.ScrollPanel = function(el, config, content){
56591 config = config || {};
56592 config.fitToFrame = true;
56593 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
56595 this.el.dom.style.overflow = "hidden";
56596 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
56597 this.el.removeClass("x-layout-inactive-content");
56598 this.el.on("mousewheel", this.onWheel, this);
56600 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
56601 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
56602 up.unselectable(); down.unselectable();
56603 up.on("click", this.scrollUp, this);
56604 down.on("click", this.scrollDown, this);
56605 up.addClassOnOver("x-scroller-btn-over");
56606 down.addClassOnOver("x-scroller-btn-over");
56607 up.addClassOnClick("x-scroller-btn-click");
56608 down.addClassOnClick("x-scroller-btn-click");
56609 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
56611 this.resizeEl = this.el;
56612 this.el = wrap; this.up = up; this.down = down;
56615 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
56617 wheelIncrement : 5,
56618 scrollUp : function(){
56619 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
56622 scrollDown : function(){
56623 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
56626 afterScroll : function(){
56627 var el = this.resizeEl;
56628 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
56629 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
56630 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
56633 setSize : function(){
56634 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
56635 this.afterScroll();
56638 onWheel : function(e){
56639 var d = e.getWheelDelta();
56640 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
56641 this.afterScroll();
56645 setContent : function(content, loadScripts){
56646 this.resizeEl.update(content, loadScripts);
56654 * @class Roo.TreePanel
56655 * @extends Roo.ContentPanel
56656 * Treepanel component
56659 * Create a new TreePanel. - defaults to fit/scoll contents.
56660 * @param {String/Object} config A string to set only the panel's title, or a config object
56662 Roo.TreePanel = function(config){
56663 var el = config.el;
56664 var tree = config.tree;
56665 delete config.tree;
56666 delete config.el; // hopefull!
56668 // wrapper for IE7 strict & safari scroll issue
56670 var treeEl = el.createChild();
56671 config.resizeEl = treeEl;
56675 Roo.TreePanel.superclass.constructor.call(this, el, config);
56678 this.tree = new Roo.tree.TreePanel(treeEl , tree);
56679 //console.log(tree);
56680 this.on('activate', function()
56682 if (this.tree.rendered) {
56685 //console.log('render tree');
56686 this.tree.render();
56688 // this should not be needed.. - it's actually the 'el' that resizes?
56689 // actuall it breaks the containerScroll - dragging nodes auto scroll at top
56691 //this.on('resize', function (cp, w, h) {
56692 // this.tree.innerCt.setWidth(w);
56693 // this.tree.innerCt.setHeight(h);
56694 // //this.tree.innerCt.setStyle('overflow-y', 'auto');
56701 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
56705 * @cfg {Roo.tree.TreePanel} tree [required] The tree TreePanel, with config etc.
56723 * Ext JS Library 1.1.1
56724 * Copyright(c) 2006-2007, Ext JS, LLC.
56726 * Originally Released Under LGPL - original licence link has changed is not relivant.
56729 * <script type="text/javascript">
56734 * @class Roo.ReaderLayout
56735 * @extends Roo.BorderLayout
56736 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
56737 * center region containing two nested regions (a top one for a list view and one for item preview below),
56738 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
56739 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
56740 * expedites the setup of the overall layout and regions for this common application style.
56743 var reader = new Roo.ReaderLayout();
56744 var CP = Roo.ContentPanel; // shortcut for adding
56746 reader.beginUpdate();
56747 reader.add("north", new CP("north", "North"));
56748 reader.add("west", new CP("west", {title: "West"}));
56749 reader.add("east", new CP("east", {title: "East"}));
56751 reader.regions.listView.add(new CP("listView", "List"));
56752 reader.regions.preview.add(new CP("preview", "Preview"));
56753 reader.endUpdate();
56756 * Create a new ReaderLayout
56757 * @param {Object} config Configuration options
56758 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
56759 * document.body if omitted)
56761 Roo.ReaderLayout = function(config, renderTo){
56762 var c = config || {size:{}};
56763 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
56764 north: c.north !== false ? Roo.apply({
56768 }, c.north) : false,
56769 west: c.west !== false ? Roo.apply({
56777 margins:{left:5,right:0,bottom:5,top:5},
56778 cmargins:{left:5,right:5,bottom:5,top:5}
56779 }, c.west) : false,
56780 east: c.east !== false ? Roo.apply({
56788 margins:{left:0,right:5,bottom:5,top:5},
56789 cmargins:{left:5,right:5,bottom:5,top:5}
56790 }, c.east) : false,
56791 center: Roo.apply({
56792 tabPosition: 'top',
56796 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
56800 this.el.addClass('x-reader');
56802 this.beginUpdate();
56804 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
56805 south: c.preview !== false ? Roo.apply({
56812 cmargins:{top:5,left:0, right:0, bottom:0}
56813 }, c.preview) : false,
56814 center: Roo.apply({
56820 this.add('center', new Roo.NestedLayoutPanel(inner,
56821 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
56825 this.regions.preview = inner.getRegion('south');
56826 this.regions.listView = inner.getRegion('center');
56829 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
56831 * Ext JS Library 1.1.1
56832 * Copyright(c) 2006-2007, Ext JS, LLC.
56834 * Originally Released Under LGPL - original licence link has changed is not relivant.
56837 * <script type="text/javascript">
56841 * @class Roo.grid.Grid
56842 * @extends Roo.util.Observable
56843 * This class represents the primary interface of a component based grid control.
56844 * <br><br>Usage:<pre><code>
56845 var grid = new Roo.grid.Grid("my-container-id", {
56848 selModel: mySelectionModel,
56849 autoSizeColumns: true,
56850 monitorWindowResize: false,
56851 trackMouseOver: true
56856 * <b>Common Problems:</b><br/>
56857 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
56858 * element will correct this<br/>
56859 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
56860 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
56861 * are unpredictable.<br/>
56862 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
56863 * grid to calculate dimensions/offsets.<br/>
56865 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
56866 * The container MUST have some type of size defined for the grid to fill. The container will be
56867 * automatically set to position relative if it isn't already.
56868 * @param {Object} config A config object that sets properties on this grid.
56870 Roo.grid.Grid = function(container, config){
56871 // initialize the container
56872 this.container = Roo.get(container);
56873 this.container.update("");
56874 this.container.setStyle("overflow", "hidden");
56875 this.container.addClass('x-grid-container');
56877 this.id = this.container.id;
56879 Roo.apply(this, config);
56880 // check and correct shorthanded configs
56882 this.dataSource = this.ds;
56886 this.colModel = this.cm;
56890 this.selModel = this.sm;
56894 if (this.selModel) {
56895 this.selModel = Roo.factory(this.selModel, Roo.grid);
56896 this.sm = this.selModel;
56897 this.sm.xmodule = this.xmodule || false;
56899 if (typeof(this.colModel.config) == 'undefined') {
56900 this.colModel = new Roo.grid.ColumnModel(this.colModel);
56901 this.cm = this.colModel;
56902 this.cm.xmodule = this.xmodule || false;
56904 if (this.dataSource) {
56905 this.dataSource= Roo.factory(this.dataSource, Roo.data);
56906 this.ds = this.dataSource;
56907 this.ds.xmodule = this.xmodule || false;
56914 this.container.setWidth(this.width);
56918 this.container.setHeight(this.height);
56925 * The raw click event for the entire grid.
56926 * @param {Roo.EventObject} e
56931 * The raw dblclick event for the entire grid.
56932 * @param {Roo.EventObject} e
56936 * @event contextmenu
56937 * The raw contextmenu event for the entire grid.
56938 * @param {Roo.EventObject} e
56940 "contextmenu" : true,
56943 * The raw mousedown event for the entire grid.
56944 * @param {Roo.EventObject} e
56946 "mousedown" : true,
56949 * The raw mouseup event for the entire grid.
56950 * @param {Roo.EventObject} e
56955 * The raw mouseover event for the entire grid.
56956 * @param {Roo.EventObject} e
56958 "mouseover" : true,
56961 * The raw mouseout event for the entire grid.
56962 * @param {Roo.EventObject} e
56967 * The raw keypress event for the entire grid.
56968 * @param {Roo.EventObject} e
56973 * The raw keydown event for the entire grid.
56974 * @param {Roo.EventObject} e
56982 * Fires when a cell is clicked
56983 * @param {Grid} this
56984 * @param {Number} rowIndex
56985 * @param {Number} columnIndex
56986 * @param {Roo.EventObject} e
56988 "cellclick" : true,
56990 * @event celldblclick
56991 * Fires when a cell is double clicked
56992 * @param {Grid} this
56993 * @param {Number} rowIndex
56994 * @param {Number} columnIndex
56995 * @param {Roo.EventObject} e
56997 "celldblclick" : true,
57000 * Fires when a row is clicked
57001 * @param {Grid} this
57002 * @param {Number} rowIndex
57003 * @param {Roo.EventObject} e
57007 * @event rowdblclick
57008 * Fires when a row is double clicked
57009 * @param {Grid} this
57010 * @param {Number} rowIndex
57011 * @param {Roo.EventObject} e
57013 "rowdblclick" : true,
57015 * @event headerclick
57016 * Fires when a header is clicked
57017 * @param {Grid} this
57018 * @param {Number} columnIndex
57019 * @param {Roo.EventObject} e
57021 "headerclick" : true,
57023 * @event headerdblclick
57024 * Fires when a header cell is double clicked
57025 * @param {Grid} this
57026 * @param {Number} columnIndex
57027 * @param {Roo.EventObject} e
57029 "headerdblclick" : true,
57031 * @event rowcontextmenu
57032 * Fires when a row is right clicked
57033 * @param {Grid} this
57034 * @param {Number} rowIndex
57035 * @param {Roo.EventObject} e
57037 "rowcontextmenu" : true,
57039 * @event cellcontextmenu
57040 * Fires when a cell is right clicked
57041 * @param {Grid} this
57042 * @param {Number} rowIndex
57043 * @param {Number} cellIndex
57044 * @param {Roo.EventObject} e
57046 "cellcontextmenu" : true,
57048 * @event headercontextmenu
57049 * Fires when a header is right clicked
57050 * @param {Grid} this
57051 * @param {Number} columnIndex
57052 * @param {Roo.EventObject} e
57054 "headercontextmenu" : true,
57056 * @event bodyscroll
57057 * Fires when the body element is scrolled
57058 * @param {Number} scrollLeft
57059 * @param {Number} scrollTop
57061 "bodyscroll" : true,
57063 * @event columnresize
57064 * Fires when the user resizes a column
57065 * @param {Number} columnIndex
57066 * @param {Number} newSize
57068 "columnresize" : true,
57070 * @event columnmove
57071 * Fires when the user moves a column
57072 * @param {Number} oldIndex
57073 * @param {Number} newIndex
57075 "columnmove" : true,
57078 * Fires when row(s) start being dragged
57079 * @param {Grid} this
57080 * @param {Roo.GridDD} dd The drag drop object
57081 * @param {event} e The raw browser event
57083 "startdrag" : true,
57086 * Fires when a drag operation is complete
57087 * @param {Grid} this
57088 * @param {Roo.GridDD} dd The drag drop object
57089 * @param {event} e The raw browser event
57094 * Fires when dragged row(s) are dropped on a valid DD target
57095 * @param {Grid} this
57096 * @param {Roo.GridDD} dd The drag drop object
57097 * @param {String} targetId The target drag drop object
57098 * @param {event} e The raw browser event
57103 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
57104 * @param {Grid} this
57105 * @param {Roo.GridDD} dd The drag drop object
57106 * @param {String} targetId The target drag drop object
57107 * @param {event} e The raw browser event
57112 * Fires when the dragged row(s) first cross another DD target while being dragged
57113 * @param {Grid} this
57114 * @param {Roo.GridDD} dd The drag drop object
57115 * @param {String} targetId The target drag drop object
57116 * @param {event} e The raw browser event
57118 "dragenter" : true,
57121 * Fires when the dragged row(s) leave another DD target while being dragged
57122 * @param {Grid} this
57123 * @param {Roo.GridDD} dd The drag drop object
57124 * @param {String} targetId The target drag drop object
57125 * @param {event} e The raw browser event
57130 * Fires when a row is rendered, so you can change add a style to it.
57131 * @param {GridView} gridview The grid view
57132 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
57138 * Fires when the grid is rendered
57139 * @param {Grid} grid
57144 Roo.grid.Grid.superclass.constructor.call(this);
57146 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
57149 * @cfg {Roo.grid.AbstractSelectionModel} sm The selection Model (default = Roo.grid.RowSelectionModel)
57152 * @cfg {Roo.grid.GridView} view The view that renders the grid (default = Roo.grid.GridView)
57155 * @cfg {Roo.grid.ColumnModel} cm[] The columns of the grid
57158 * @cfg {Roo.grid.Store} ds The data store for the grid
57161 * @cfg {Roo.Toolbar} toolbar a toolbar for buttons etc.
57164 * @cfg {String} ddGroup - drag drop group.
57167 * @cfg {String} dragGroup - drag group (?? not sure if needed.)
57171 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
57173 minColumnWidth : 25,
57176 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
57177 * <b>on initial render.</b> It is more efficient to explicitly size the columns
57178 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
57180 autoSizeColumns : false,
57183 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
57185 autoSizeHeaders : true,
57188 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
57190 monitorWindowResize : true,
57193 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
57194 * rows measured to get a columns size. Default is 0 (all rows).
57196 maxRowsToMeasure : 0,
57199 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
57201 trackMouseOver : true,
57204 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
57207 * @cfg {Boolean} enableDrop True to enable drop of elements. Default is false. (double check if this is needed?)
57211 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
57213 enableDragDrop : false,
57216 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
57218 enableColumnMove : true,
57221 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
57223 enableColumnHide : true,
57226 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
57228 enableRowHeightSync : false,
57231 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
57236 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
57238 autoHeight : false,
57241 * @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.
57243 autoExpandColumn : false,
57246 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
57249 autoExpandMin : 50,
57252 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
57254 autoExpandMax : 1000,
57257 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
57262 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
57266 * @cfg {Roo.dd.DropTarget} dropTarget An {@link Roo.dd.DropTarget} config
57276 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
57277 * of a fixed width. Default is false.
57280 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
57285 * @cfg {String} ddText Configures the text is the drag proxy (defaults to "%0 selected row(s)").
57286 * %0 is replaced with the number of selected rows.
57288 ddText : "{0} selected row{1}",
57292 * Called once after all setup has been completed and the grid is ready to be rendered.
57293 * @return {Roo.grid.Grid} this
57295 render : function()
57297 var c = this.container;
57298 // try to detect autoHeight/width mode
57299 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
57300 this.autoHeight = true;
57302 var view = this.getView();
57305 c.on("click", this.onClick, this);
57306 c.on("dblclick", this.onDblClick, this);
57307 c.on("contextmenu", this.onContextMenu, this);
57308 c.on("keydown", this.onKeyDown, this);
57310 c.on("touchstart", this.onTouchStart, this);
57313 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
57315 this.getSelectionModel().init(this);
57320 this.loadMask = new Roo.LoadMask(this.container,
57321 Roo.apply({store:this.dataSource}, this.loadMask));
57325 if (this.toolbar && this.toolbar.xtype) {
57326 this.toolbar.container = this.getView().getHeaderPanel(true);
57327 this.toolbar = new Roo.Toolbar(this.toolbar);
57329 if (this.footer && this.footer.xtype) {
57330 this.footer.dataSource = this.getDataSource();
57331 this.footer.container = this.getView().getFooterPanel(true);
57332 this.footer = Roo.factory(this.footer, Roo);
57334 if (this.dropTarget && this.dropTarget.xtype) {
57335 delete this.dropTarget.xtype;
57336 this.dropTarget = new Roo.dd.DropTarget(this.getView().mainBody, this.dropTarget);
57340 this.rendered = true;
57341 this.fireEvent('render', this);
57346 * Reconfigures the grid to use a different Store and Column Model.
57347 * The View will be bound to the new objects and refreshed.
57348 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
57349 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
57351 reconfigure : function(dataSource, colModel){
57353 this.loadMask.destroy();
57354 this.loadMask = new Roo.LoadMask(this.container,
57355 Roo.apply({store:dataSource}, this.loadMask));
57357 this.view.bind(dataSource, colModel);
57358 this.dataSource = dataSource;
57359 this.colModel = colModel;
57360 this.view.refresh(true);
57364 * Add's a column, default at the end..
57366 * @param {int} position to add (default end)
57367 * @param {Array} of objects of column configuration see {@link Roo.grid.ColumnModel}
57369 addColumns : function(pos, ar)
57372 for (var i =0;i< ar.length;i++) {
57374 cfg.id = typeof(cfg.id) == 'undefined' ? Roo.id() : cfg.id; // don't normally use this..
57375 this.cm.lookup[cfg.id] = cfg;
57379 if (typeof(pos) == 'undefined' || pos >= this.cm.config.length) {
57380 pos = this.cm.config.length; //this.cm.config.push(cfg);
57382 pos = Math.max(0,pos);
57385 this.cm.config.splice.apply(this.cm.config, ar);
57389 this.view.generateRules(this.cm);
57390 this.view.refresh(true);
57398 onKeyDown : function(e){
57399 this.fireEvent("keydown", e);
57403 * Destroy this grid.
57404 * @param {Boolean} removeEl True to remove the element
57406 destroy : function(removeEl, keepListeners){
57408 this.loadMask.destroy();
57410 var c = this.container;
57411 c.removeAllListeners();
57412 this.view.destroy();
57413 this.colModel.purgeListeners();
57414 if(!keepListeners){
57415 this.purgeListeners();
57418 if(removeEl === true){
57424 processEvent : function(name, e){
57425 // does this fire select???
57426 //Roo.log('grid:processEvent ' + name);
57428 if (name != 'touchstart' ) {
57429 this.fireEvent(name, e);
57432 var t = e.getTarget();
57434 var header = v.findHeaderIndex(t);
57435 if(header !== false){
57436 var ename = name == 'touchstart' ? 'click' : name;
57438 this.fireEvent("header" + ename, this, header, e);
57440 var row = v.findRowIndex(t);
57441 var cell = v.findCellIndex(t);
57442 if (name == 'touchstart') {
57443 // first touch is always a click.
57444 // hopefull this happens after selection is updated.?
57447 if (typeof(this.selModel.getSelectedCell) != 'undefined') {
57448 var cs = this.selModel.getSelectedCell();
57449 if (row == cs[0] && cell == cs[1]){
57453 if (typeof(this.selModel.getSelections) != 'undefined') {
57454 var cs = this.selModel.getSelections();
57455 var ds = this.dataSource;
57456 if (cs.length == 1 && ds.getAt(row) == cs[0]){
57467 this.fireEvent("row" + name, this, row, e);
57468 if(cell !== false){
57469 this.fireEvent("cell" + name, this, row, cell, e);
57476 onClick : function(e){
57477 this.processEvent("click", e);
57480 onTouchStart : function(e){
57481 this.processEvent("touchstart", e);
57485 onContextMenu : function(e, t){
57486 this.processEvent("contextmenu", e);
57490 onDblClick : function(e){
57491 this.processEvent("dblclick", e);
57495 walkCells : function(row, col, step, fn, scope){
57496 var cm = this.colModel, clen = cm.getColumnCount();
57497 var ds = this.dataSource, rlen = ds.getCount(), first = true;
57509 if(fn.call(scope || this, row, col, cm) === true){
57527 if(fn.call(scope || this, row, col, cm) === true){
57539 getSelections : function(){
57540 return this.selModel.getSelections();
57544 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
57545 * but if manual update is required this method will initiate it.
57547 autoSize : function(){
57549 this.view.layout();
57550 if(this.view.adjustForScroll){
57551 this.view.adjustForScroll();
57557 * Returns the grid's underlying element.
57558 * @return {Element} The element
57560 getGridEl : function(){
57561 return this.container;
57564 // private for compatibility, overridden by editor grid
57565 stopEditing : function(){},
57568 * Returns the grid's SelectionModel.
57569 * @return {SelectionModel}
57571 getSelectionModel : function(){
57572 if(!this.selModel){
57573 this.selModel = new Roo.grid.RowSelectionModel();
57575 return this.selModel;
57579 * Returns the grid's DataSource.
57580 * @return {DataSource}
57582 getDataSource : function(){
57583 return this.dataSource;
57587 * Returns the grid's ColumnModel.
57588 * @return {ColumnModel}
57590 getColumnModel : function(){
57591 return this.colModel;
57595 * Returns the grid's GridView object.
57596 * @return {GridView}
57598 getView : function(){
57600 this.view = new Roo.grid.GridView(this.viewConfig);
57601 this.relayEvents(this.view, [
57602 "beforerowremoved", "beforerowsinserted",
57603 "beforerefresh", "rowremoved",
57604 "rowsinserted", "rowupdated" ,"refresh"
57610 * Called to get grid's drag proxy text, by default returns this.ddText.
57611 * Override this to put something different in the dragged text.
57614 getDragDropText : function(){
57615 var count = this.selModel.getCount();
57616 return String.format(this.ddText, count, count == 1 ? '' : 's');
57621 * Ext JS Library 1.1.1
57622 * Copyright(c) 2006-2007, Ext JS, LLC.
57624 * Originally Released Under LGPL - original licence link has changed is not relivant.
57627 * <script type="text/javascript">
57630 * @class Roo.grid.AbstractGridView
57631 * @extends Roo.util.Observable
57633 * Abstract base class for grid Views
57636 Roo.grid.AbstractGridView = function(){
57640 "beforerowremoved" : true,
57641 "beforerowsinserted" : true,
57642 "beforerefresh" : true,
57643 "rowremoved" : true,
57644 "rowsinserted" : true,
57645 "rowupdated" : true,
57648 Roo.grid.AbstractGridView.superclass.constructor.call(this);
57651 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
57652 rowClass : "x-grid-row",
57653 cellClass : "x-grid-cell",
57654 tdClass : "x-grid-td",
57655 hdClass : "x-grid-hd",
57656 splitClass : "x-grid-hd-split",
57658 init: function(grid){
57660 var cid = this.grid.getGridEl().id;
57661 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
57662 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
57663 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
57664 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
57667 getColumnRenderers : function(){
57668 var renderers = [];
57669 var cm = this.grid.colModel;
57670 var colCount = cm.getColumnCount();
57671 for(var i = 0; i < colCount; i++){
57672 renderers[i] = cm.getRenderer(i);
57677 getColumnIds : function(){
57679 var cm = this.grid.colModel;
57680 var colCount = cm.getColumnCount();
57681 for(var i = 0; i < colCount; i++){
57682 ids[i] = cm.getColumnId(i);
57687 getDataIndexes : function(){
57688 if(!this.indexMap){
57689 this.indexMap = this.buildIndexMap();
57691 return this.indexMap.colToData;
57694 getColumnIndexByDataIndex : function(dataIndex){
57695 if(!this.indexMap){
57696 this.indexMap = this.buildIndexMap();
57698 return this.indexMap.dataToCol[dataIndex];
57702 * Set a css style for a column dynamically.
57703 * @param {Number} colIndex The index of the column
57704 * @param {String} name The css property name
57705 * @param {String} value The css value
57707 setCSSStyle : function(colIndex, name, value){
57708 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
57709 Roo.util.CSS.updateRule(selector, name, value);
57712 generateRules : function(cm){
57713 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
57714 Roo.util.CSS.removeStyleSheet(rulesId);
57715 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
57716 var cid = cm.getColumnId(i);
57717 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
57718 this.tdSelector, cid, " {\n}\n",
57719 this.hdSelector, cid, " {\n}\n",
57720 this.splitSelector, cid, " {\n}\n");
57722 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
57726 * Ext JS Library 1.1.1
57727 * Copyright(c) 2006-2007, Ext JS, LLC.
57729 * Originally Released Under LGPL - original licence link has changed is not relivant.
57732 * <script type="text/javascript">
57736 // This is a support class used internally by the Grid components
57737 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
57739 this.view = grid.getView();
57740 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
57741 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
57743 this.setHandleElId(Roo.id(hd));
57744 this.setOuterHandleElId(Roo.id(hd2));
57746 this.scroll = false;
57748 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
57750 getDragData : function(e){
57751 var t = Roo.lib.Event.getTarget(e);
57752 var h = this.view.findHeaderCell(t);
57754 return {ddel: h.firstChild, header:h};
57759 onInitDrag : function(e){
57760 this.view.headersDisabled = true;
57761 var clone = this.dragData.ddel.cloneNode(true);
57762 clone.id = Roo.id();
57763 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
57764 this.proxy.update(clone);
57768 afterValidDrop : function(){
57770 setTimeout(function(){
57771 v.headersDisabled = false;
57775 afterInvalidDrop : function(){
57777 setTimeout(function(){
57778 v.headersDisabled = false;
57784 * Ext JS Library 1.1.1
57785 * Copyright(c) 2006-2007, Ext JS, LLC.
57787 * Originally Released Under LGPL - original licence link has changed is not relivant.
57790 * <script type="text/javascript">
57793 // This is a support class used internally by the Grid components
57794 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
57796 this.view = grid.getView();
57797 // split the proxies so they don't interfere with mouse events
57798 this.proxyTop = Roo.DomHelper.append(document.body, {
57799 cls:"col-move-top", html:" "
57801 this.proxyBottom = Roo.DomHelper.append(document.body, {
57802 cls:"col-move-bottom", html:" "
57804 this.proxyTop.hide = this.proxyBottom.hide = function(){
57805 this.setLeftTop(-100,-100);
57806 this.setStyle("visibility", "hidden");
57808 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
57809 // temporarily disabled
57810 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
57811 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
57813 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
57814 proxyOffsets : [-4, -9],
57815 fly: Roo.Element.fly,
57817 getTargetFromEvent : function(e){
57818 var t = Roo.lib.Event.getTarget(e);
57819 var cindex = this.view.findCellIndex(t);
57820 if(cindex !== false){
57821 return this.view.getHeaderCell(cindex);
57826 nextVisible : function(h){
57827 var v = this.view, cm = this.grid.colModel;
57830 if(!cm.isHidden(v.getCellIndex(h))){
57838 prevVisible : function(h){
57839 var v = this.view, cm = this.grid.colModel;
57842 if(!cm.isHidden(v.getCellIndex(h))){
57850 positionIndicator : function(h, n, e){
57851 var x = Roo.lib.Event.getPageX(e);
57852 var r = Roo.lib.Dom.getRegion(n.firstChild);
57853 var px, pt, py = r.top + this.proxyOffsets[1];
57854 if((r.right - x) <= (r.right-r.left)/2){
57855 px = r.right+this.view.borderWidth;
57861 var oldIndex = this.view.getCellIndex(h);
57862 var newIndex = this.view.getCellIndex(n);
57864 if(this.grid.colModel.isFixed(newIndex)){
57868 var locked = this.grid.colModel.isLocked(newIndex);
57873 if(oldIndex < newIndex){
57876 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
57879 px += this.proxyOffsets[0];
57880 this.proxyTop.setLeftTop(px, py);
57881 this.proxyTop.show();
57882 if(!this.bottomOffset){
57883 this.bottomOffset = this.view.mainHd.getHeight();
57885 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
57886 this.proxyBottom.show();
57890 onNodeEnter : function(n, dd, e, data){
57891 if(data.header != n){
57892 this.positionIndicator(data.header, n, e);
57896 onNodeOver : function(n, dd, e, data){
57897 var result = false;
57898 if(data.header != n){
57899 result = this.positionIndicator(data.header, n, e);
57902 this.proxyTop.hide();
57903 this.proxyBottom.hide();
57905 return result ? this.dropAllowed : this.dropNotAllowed;
57908 onNodeOut : function(n, dd, e, data){
57909 this.proxyTop.hide();
57910 this.proxyBottom.hide();
57913 onNodeDrop : function(n, dd, e, data){
57914 var h = data.header;
57916 var cm = this.grid.colModel;
57917 var x = Roo.lib.Event.getPageX(e);
57918 var r = Roo.lib.Dom.getRegion(n.firstChild);
57919 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
57920 var oldIndex = this.view.getCellIndex(h);
57921 var newIndex = this.view.getCellIndex(n);
57922 var locked = cm.isLocked(newIndex);
57926 if(oldIndex < newIndex){
57929 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
57932 cm.setLocked(oldIndex, locked, true);
57933 cm.moveColumn(oldIndex, newIndex);
57934 this.grid.fireEvent("columnmove", oldIndex, newIndex);
57942 * Ext JS Library 1.1.1
57943 * Copyright(c) 2006-2007, Ext JS, LLC.
57945 * Originally Released Under LGPL - original licence link has changed is not relivant.
57948 * <script type="text/javascript">
57952 * @class Roo.grid.GridView
57953 * @extends Roo.util.Observable
57956 * @param {Object} config
57958 Roo.grid.GridView = function(config){
57959 Roo.grid.GridView.superclass.constructor.call(this);
57962 Roo.apply(this, config);
57965 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
57967 unselectable : 'unselectable="on"',
57968 unselectableCls : 'x-unselectable',
57971 rowClass : "x-grid-row",
57973 cellClass : "x-grid-col",
57975 tdClass : "x-grid-td",
57977 hdClass : "x-grid-hd",
57979 splitClass : "x-grid-split",
57981 sortClasses : ["sort-asc", "sort-desc"],
57983 enableMoveAnim : false,
57987 dh : Roo.DomHelper,
57989 fly : Roo.Element.fly,
57991 css : Roo.util.CSS,
57997 scrollIncrement : 22,
57999 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
58001 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
58003 bind : function(ds, cm){
58005 this.ds.un("load", this.onLoad, this);
58006 this.ds.un("datachanged", this.onDataChange, this);
58007 this.ds.un("add", this.onAdd, this);
58008 this.ds.un("remove", this.onRemove, this);
58009 this.ds.un("update", this.onUpdate, this);
58010 this.ds.un("clear", this.onClear, this);
58013 ds.on("load", this.onLoad, this);
58014 ds.on("datachanged", this.onDataChange, this);
58015 ds.on("add", this.onAdd, this);
58016 ds.on("remove", this.onRemove, this);
58017 ds.on("update", this.onUpdate, this);
58018 ds.on("clear", this.onClear, this);
58023 this.cm.un("widthchange", this.onColWidthChange, this);
58024 this.cm.un("headerchange", this.onHeaderChange, this);
58025 this.cm.un("hiddenchange", this.onHiddenChange, this);
58026 this.cm.un("columnmoved", this.onColumnMove, this);
58027 this.cm.un("columnlockchange", this.onColumnLock, this);
58030 this.generateRules(cm);
58031 cm.on("widthchange", this.onColWidthChange, this);
58032 cm.on("headerchange", this.onHeaderChange, this);
58033 cm.on("hiddenchange", this.onHiddenChange, this);
58034 cm.on("columnmoved", this.onColumnMove, this);
58035 cm.on("columnlockchange", this.onColumnLock, this);
58040 init: function(grid){
58041 Roo.grid.GridView.superclass.init.call(this, grid);
58043 this.bind(grid.dataSource, grid.colModel);
58045 grid.on("headerclick", this.handleHeaderClick, this);
58047 if(grid.trackMouseOver){
58048 grid.on("mouseover", this.onRowOver, this);
58049 grid.on("mouseout", this.onRowOut, this);
58051 grid.cancelTextSelection = function(){};
58052 this.gridId = grid.id;
58054 var tpls = this.templates || {};
58057 tpls.master = new Roo.Template(
58058 '<div class="x-grid" hidefocus="true">',
58059 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
58060 '<div class="x-grid-topbar"></div>',
58061 '<div class="x-grid-scroller"><div></div></div>',
58062 '<div class="x-grid-locked">',
58063 '<div class="x-grid-header">{lockedHeader}</div>',
58064 '<div class="x-grid-body">{lockedBody}</div>',
58066 '<div class="x-grid-viewport">',
58067 '<div class="x-grid-header">{header}</div>',
58068 '<div class="x-grid-body">{body}</div>',
58070 '<div class="x-grid-bottombar"></div>',
58072 '<div class="x-grid-resize-proxy"> </div>',
58075 tpls.master.disableformats = true;
58079 tpls.header = new Roo.Template(
58080 '<table border="0" cellspacing="0" cellpadding="0">',
58081 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
58084 tpls.header.disableformats = true;
58086 tpls.header.compile();
58089 tpls.hcell = new Roo.Template(
58090 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
58091 '<div class="x-grid-hd-text ' + this.unselectableCls + '" ' + this.unselectable +'>{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
58094 tpls.hcell.disableFormats = true;
58096 tpls.hcell.compile();
58099 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style} ' +
58100 this.unselectableCls + '" ' + this.unselectable +'> </div>');
58101 tpls.hsplit.disableFormats = true;
58103 tpls.hsplit.compile();
58106 tpls.body = new Roo.Template(
58107 '<table border="0" cellspacing="0" cellpadding="0">',
58108 "<tbody>{rows}</tbody>",
58111 tpls.body.disableFormats = true;
58113 tpls.body.compile();
58116 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
58117 tpls.row.disableFormats = true;
58119 tpls.row.compile();
58122 tpls.cell = new Roo.Template(
58123 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
58124 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text ' +
58125 this.unselectableCls + '" ' + this.unselectable +'" {attr}>{value}</div></div>',
58128 tpls.cell.disableFormats = true;
58130 tpls.cell.compile();
58132 this.templates = tpls;
58135 // remap these for backwards compat
58136 onColWidthChange : function(){
58137 this.updateColumns.apply(this, arguments);
58139 onHeaderChange : function(){
58140 this.updateHeaders.apply(this, arguments);
58142 onHiddenChange : function(){
58143 this.handleHiddenChange.apply(this, arguments);
58145 onColumnMove : function(){
58146 this.handleColumnMove.apply(this, arguments);
58148 onColumnLock : function(){
58149 this.handleLockChange.apply(this, arguments);
58152 onDataChange : function(){
58154 this.updateHeaderSortState();
58157 onClear : function(){
58161 onUpdate : function(ds, record){
58162 this.refreshRow(record);
58165 refreshRow : function(record){
58166 var ds = this.ds, index;
58167 if(typeof record == 'number'){
58169 record = ds.getAt(index);
58171 index = ds.indexOf(record);
58173 this.insertRows(ds, index, index, true);
58174 this.onRemove(ds, record, index+1, true);
58175 this.syncRowHeights(index, index);
58177 this.fireEvent("rowupdated", this, index, record);
58180 onAdd : function(ds, records, index){
58181 this.insertRows(ds, index, index + (records.length-1));
58184 onRemove : function(ds, record, index, isUpdate){
58185 if(isUpdate !== true){
58186 this.fireEvent("beforerowremoved", this, index, record);
58188 var bt = this.getBodyTable(), lt = this.getLockedTable();
58189 if(bt.rows[index]){
58190 bt.firstChild.removeChild(bt.rows[index]);
58192 if(lt.rows[index]){
58193 lt.firstChild.removeChild(lt.rows[index]);
58195 if(isUpdate !== true){
58196 this.stripeRows(index);
58197 this.syncRowHeights(index, index);
58199 this.fireEvent("rowremoved", this, index, record);
58203 onLoad : function(){
58204 this.scrollToTop();
58208 * Scrolls the grid to the top
58210 scrollToTop : function(){
58212 this.scroller.dom.scrollTop = 0;
58218 * Gets a panel in the header of the grid that can be used for toolbars etc.
58219 * After modifying the contents of this panel a call to grid.autoSize() may be
58220 * required to register any changes in size.
58221 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
58222 * @return Roo.Element
58224 getHeaderPanel : function(doShow){
58226 this.headerPanel.show();
58228 return this.headerPanel;
58232 * Gets a panel in the footer of the grid that can be used for toolbars etc.
58233 * After modifying the contents of this panel a call to grid.autoSize() may be
58234 * required to register any changes in size.
58235 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
58236 * @return Roo.Element
58238 getFooterPanel : function(doShow){
58240 this.footerPanel.show();
58242 return this.footerPanel;
58245 initElements : function(){
58246 var E = Roo.Element;
58247 var el = this.grid.getGridEl().dom.firstChild;
58248 var cs = el.childNodes;
58250 this.el = new E(el);
58252 this.focusEl = new E(el.firstChild);
58253 this.focusEl.swallowEvent("click", true);
58255 this.headerPanel = new E(cs[1]);
58256 this.headerPanel.enableDisplayMode("block");
58258 this.scroller = new E(cs[2]);
58259 this.scrollSizer = new E(this.scroller.dom.firstChild);
58261 this.lockedWrap = new E(cs[3]);
58262 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
58263 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
58265 this.mainWrap = new E(cs[4]);
58266 this.mainHd = new E(this.mainWrap.dom.firstChild);
58267 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
58269 this.footerPanel = new E(cs[5]);
58270 this.footerPanel.enableDisplayMode("block");
58272 this.resizeProxy = new E(cs[6]);
58274 this.headerSelector = String.format(
58275 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
58276 this.lockedHd.id, this.mainHd.id
58279 this.splitterSelector = String.format(
58280 '#{0} div.x-grid-split, #{1} div.x-grid-split',
58281 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
58284 idToCssName : function(s)
58286 return s.replace(/[^a-z0-9]+/ig, '-');
58289 getHeaderCell : function(index){
58290 return Roo.DomQuery.select(this.headerSelector)[index];
58293 getHeaderCellMeasure : function(index){
58294 return this.getHeaderCell(index).firstChild;
58297 getHeaderCellText : function(index){
58298 return this.getHeaderCell(index).firstChild.firstChild;
58301 getLockedTable : function(){
58302 return this.lockedBody.dom.firstChild;
58305 getBodyTable : function(){
58306 return this.mainBody.dom.firstChild;
58309 getLockedRow : function(index){
58310 return this.getLockedTable().rows[index];
58313 getRow : function(index){
58314 return this.getBodyTable().rows[index];
58317 getRowComposite : function(index){
58319 this.rowEl = new Roo.CompositeElementLite();
58321 var els = [], lrow, mrow;
58322 if(lrow = this.getLockedRow(index)){
58325 if(mrow = this.getRow(index)){
58328 this.rowEl.elements = els;
58332 * Gets the 'td' of the cell
58334 * @param {Integer} rowIndex row to select
58335 * @param {Integer} colIndex column to select
58339 getCell : function(rowIndex, colIndex){
58340 var locked = this.cm.getLockedCount();
58342 if(colIndex < locked){
58343 source = this.lockedBody.dom.firstChild;
58345 source = this.mainBody.dom.firstChild;
58346 colIndex -= locked;
58348 return source.rows[rowIndex].childNodes[colIndex];
58351 getCellText : function(rowIndex, colIndex){
58352 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
58355 getCellBox : function(cell){
58356 var b = this.fly(cell).getBox();
58357 if(Roo.isOpera){ // opera fails to report the Y
58358 b.y = cell.offsetTop + this.mainBody.getY();
58363 getCellIndex : function(cell){
58364 var id = String(cell.className).match(this.cellRE);
58366 return parseInt(id[1], 10);
58371 findHeaderIndex : function(n){
58372 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
58373 return r ? this.getCellIndex(r) : false;
58376 findHeaderCell : function(n){
58377 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
58378 return r ? r : false;
58381 findRowIndex : function(n){
58385 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
58386 return r ? r.rowIndex : false;
58389 findCellIndex : function(node){
58390 var stop = this.el.dom;
58391 while(node && node != stop){
58392 if(this.findRE.test(node.className)){
58393 return this.getCellIndex(node);
58395 node = node.parentNode;
58400 getColumnId : function(index){
58401 return this.cm.getColumnId(index);
58404 getSplitters : function()
58406 if(this.splitterSelector){
58407 return Roo.DomQuery.select(this.splitterSelector);
58413 getSplitter : function(index){
58414 return this.getSplitters()[index];
58417 onRowOver : function(e, t){
58419 if((row = this.findRowIndex(t)) !== false){
58420 this.getRowComposite(row).addClass("x-grid-row-over");
58424 onRowOut : function(e, t){
58426 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
58427 this.getRowComposite(row).removeClass("x-grid-row-over");
58431 renderHeaders : function(){
58433 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
58434 var cb = [], lb = [], sb = [], lsb = [], p = {};
58435 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
58436 p.cellId = "x-grid-hd-0-" + i;
58437 p.splitId = "x-grid-csplit-0-" + i;
58438 p.id = cm.getColumnId(i);
58439 p.value = cm.getColumnHeader(i) || "";
58440 p.title = cm.getColumnTooltip(i) || (''+p.value).match(/\</) ? '' : p.value || "";
58441 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
58442 if(!cm.isLocked(i)){
58443 cb[cb.length] = ct.apply(p);
58444 sb[sb.length] = st.apply(p);
58446 lb[lb.length] = ct.apply(p);
58447 lsb[lsb.length] = st.apply(p);
58450 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
58451 ht.apply({cells: cb.join(""), splits:sb.join("")})];
58454 updateHeaders : function(){
58455 var html = this.renderHeaders();
58456 this.lockedHd.update(html[0]);
58457 this.mainHd.update(html[1]);
58461 * Focuses the specified row.
58462 * @param {Number} row The row index
58464 focusRow : function(row)
58466 //Roo.log('GridView.focusRow');
58467 var x = this.scroller.dom.scrollLeft;
58468 this.focusCell(row, 0, false);
58469 this.scroller.dom.scrollLeft = x;
58473 * Focuses the specified cell.
58474 * @param {Number} row The row index
58475 * @param {Number} col The column index
58476 * @param {Boolean} hscroll false to disable horizontal scrolling
58478 focusCell : function(row, col, hscroll)
58480 //Roo.log('GridView.focusCell');
58481 var el = this.ensureVisible(row, col, hscroll);
58482 this.focusEl.alignTo(el, "tl-tl");
58484 this.focusEl.focus();
58486 this.focusEl.focus.defer(1, this.focusEl);
58491 * Scrolls the specified cell into view
58492 * @param {Number} row The row index
58493 * @param {Number} col The column index
58494 * @param {Boolean} hscroll false to disable horizontal scrolling
58496 ensureVisible : function(row, col, hscroll)
58498 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
58499 //return null; //disable for testing.
58500 if(typeof row != "number"){
58501 row = row.rowIndex;
58503 if(row < 0 && row >= this.ds.getCount()){
58506 col = (col !== undefined ? col : 0);
58507 var cm = this.grid.colModel;
58508 while(cm.isHidden(col)){
58512 var el = this.getCell(row, col);
58516 var c = this.scroller.dom;
58518 var ctop = parseInt(el.offsetTop, 10);
58519 var cleft = parseInt(el.offsetLeft, 10);
58520 var cbot = ctop + el.offsetHeight;
58521 var cright = cleft + el.offsetWidth;
58523 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
58524 var stop = parseInt(c.scrollTop, 10);
58525 var sleft = parseInt(c.scrollLeft, 10);
58526 var sbot = stop + ch;
58527 var sright = sleft + c.clientWidth;
58529 Roo.log('GridView.ensureVisible:' +
58531 ' c.clientHeight:' + c.clientHeight +
58532 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
58540 c.scrollTop = ctop;
58541 //Roo.log("set scrolltop to ctop DISABLE?");
58542 }else if(cbot > sbot){
58543 //Roo.log("set scrolltop to cbot-ch");
58544 c.scrollTop = cbot-ch;
58547 if(hscroll !== false){
58549 c.scrollLeft = cleft;
58550 }else if(cright > sright){
58551 c.scrollLeft = cright-c.clientWidth;
58558 updateColumns : function(){
58559 this.grid.stopEditing();
58560 var cm = this.grid.colModel, colIds = this.getColumnIds();
58561 //var totalWidth = cm.getTotalWidth();
58563 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
58564 //if(cm.isHidden(i)) continue;
58565 var w = cm.getColumnWidth(i);
58566 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
58567 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
58569 this.updateSplitters();
58572 generateRules : function(cm){
58573 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
58574 Roo.util.CSS.removeStyleSheet(rulesId);
58575 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
58576 var cid = cm.getColumnId(i);
58578 if(cm.config[i].align){
58579 align = 'text-align:'+cm.config[i].align+';';
58582 if(cm.isHidden(i)){
58583 hidden = 'display:none;';
58585 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
58587 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
58588 this.hdSelector, cid, " {\n", align, width, "}\n",
58589 this.tdSelector, cid, " {\n",hidden,"\n}\n",
58590 this.splitSelector, cid, " {\n", hidden , "\n}\n");
58592 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
58595 updateSplitters : function(){
58596 var cm = this.cm, s = this.getSplitters();
58597 if(s){ // splitters not created yet
58598 var pos = 0, locked = true;
58599 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
58600 if(cm.isHidden(i)) {
58603 var w = cm.getColumnWidth(i); // make sure it's a number
58604 if(!cm.isLocked(i) && locked){
58609 s[i].style.left = (pos-this.splitOffset) + "px";
58614 handleHiddenChange : function(colModel, colIndex, hidden){
58616 this.hideColumn(colIndex);
58618 this.unhideColumn(colIndex);
58622 hideColumn : function(colIndex){
58623 var cid = this.getColumnId(colIndex);
58624 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
58625 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
58627 this.updateHeaders();
58629 this.updateSplitters();
58633 unhideColumn : function(colIndex){
58634 var cid = this.getColumnId(colIndex);
58635 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
58636 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
58639 this.updateHeaders();
58641 this.updateSplitters();
58645 insertRows : function(dm, firstRow, lastRow, isUpdate){
58646 if(firstRow == 0 && lastRow == dm.getCount()-1){
58650 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
58652 var s = this.getScrollState();
58653 var markup = this.renderRows(firstRow, lastRow);
58654 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
58655 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
58656 this.restoreScroll(s);
58658 this.fireEvent("rowsinserted", this, firstRow, lastRow);
58659 this.syncRowHeights(firstRow, lastRow);
58660 this.stripeRows(firstRow);
58666 bufferRows : function(markup, target, index){
58667 var before = null, trows = target.rows, tbody = target.tBodies[0];
58668 if(index < trows.length){
58669 before = trows[index];
58671 var b = document.createElement("div");
58672 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
58673 var rows = b.firstChild.rows;
58674 for(var i = 0, len = rows.length; i < len; i++){
58676 tbody.insertBefore(rows[0], before);
58678 tbody.appendChild(rows[0]);
58685 deleteRows : function(dm, firstRow, lastRow){
58686 if(dm.getRowCount()<1){
58687 this.fireEvent("beforerefresh", this);
58688 this.mainBody.update("");
58689 this.lockedBody.update("");
58690 this.fireEvent("refresh", this);
58692 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
58693 var bt = this.getBodyTable();
58694 var tbody = bt.firstChild;
58695 var rows = bt.rows;
58696 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
58697 tbody.removeChild(rows[firstRow]);
58699 this.stripeRows(firstRow);
58700 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
58704 updateRows : function(dataSource, firstRow, lastRow){
58705 var s = this.getScrollState();
58707 this.restoreScroll(s);
58710 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
58714 this.updateHeaderSortState();
58717 getScrollState : function(){
58719 var sb = this.scroller.dom;
58720 return {left: sb.scrollLeft, top: sb.scrollTop};
58723 stripeRows : function(startRow){
58724 if(!this.grid.stripeRows || this.ds.getCount() < 1){
58727 startRow = startRow || 0;
58728 var rows = this.getBodyTable().rows;
58729 var lrows = this.getLockedTable().rows;
58730 var cls = ' x-grid-row-alt ';
58731 for(var i = startRow, len = rows.length; i < len; i++){
58732 var row = rows[i], lrow = lrows[i];
58733 var isAlt = ((i+1) % 2 == 0);
58734 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
58735 if(isAlt == hasAlt){
58739 row.className += " x-grid-row-alt";
58741 row.className = row.className.replace("x-grid-row-alt", "");
58744 lrow.className = row.className;
58749 restoreScroll : function(state){
58750 //Roo.log('GridView.restoreScroll');
58751 var sb = this.scroller.dom;
58752 sb.scrollLeft = state.left;
58753 sb.scrollTop = state.top;
58757 syncScroll : function(){
58758 //Roo.log('GridView.syncScroll');
58759 var sb = this.scroller.dom;
58760 var sh = this.mainHd.dom;
58761 var bs = this.mainBody.dom;
58762 var lv = this.lockedBody.dom;
58763 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
58764 lv.scrollTop = bs.scrollTop = sb.scrollTop;
58767 handleScroll : function(e){
58769 var sb = this.scroller.dom;
58770 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
58774 handleWheel : function(e){
58775 var d = e.getWheelDelta();
58776 this.scroller.dom.scrollTop -= d*22;
58777 // set this here to prevent jumpy scrolling on large tables
58778 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
58782 renderRows : function(startRow, endRow){
58783 // pull in all the crap needed to render rows
58784 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
58785 var colCount = cm.getColumnCount();
58787 if(ds.getCount() < 1){
58791 // build a map for all the columns
58793 for(var i = 0; i < colCount; i++){
58794 var name = cm.getDataIndex(i);
58796 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
58797 renderer : cm.getRenderer(i),
58798 id : cm.getColumnId(i),
58799 locked : cm.isLocked(i),
58800 has_editor : cm.isCellEditable(i)
58804 startRow = startRow || 0;
58805 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
58807 // records to render
58808 var rs = ds.getRange(startRow, endRow);
58810 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
58813 // As much as I hate to duplicate code, this was branched because FireFox really hates
58814 // [].join("") on strings. The performance difference was substantial enough to
58815 // branch this function
58816 doRender : Roo.isGecko ?
58817 function(cs, rs, ds, startRow, colCount, stripe){
58818 var ts = this.templates, ct = ts.cell, rt = ts.row;
58820 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
58822 var hasListener = this.grid.hasListener('rowclass');
58824 for(var j = 0, len = rs.length; j < len; j++){
58825 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
58826 for(var i = 0; i < colCount; i++){
58828 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
58830 p.css = p.attr = "";
58831 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
58832 if(p.value == undefined || p.value === "") {
58833 p.value = " ";
58836 p.css += ' x-grid-editable-cell';
58838 if(c.dirty && typeof r.modified[c.name] !== 'undefined'){
58839 p.css += ' x-grid-dirty-cell';
58841 var markup = ct.apply(p);
58849 if(stripe && ((rowIndex+1) % 2 == 0)){
58850 alt.push("x-grid-row-alt")
58853 alt.push( " x-grid-dirty-row");
58856 if(this.getRowClass){
58857 alt.push(this.getRowClass(r, rowIndex));
58863 rowIndex : rowIndex,
58866 this.grid.fireEvent('rowclass', this, rowcfg);
58867 alt.push(rowcfg.rowClass);
58869 rp.alt = alt.join(" ");
58870 lbuf+= rt.apply(rp);
58872 buf+= rt.apply(rp);
58874 return [lbuf, buf];
58876 function(cs, rs, ds, startRow, colCount, stripe){
58877 var ts = this.templates, ct = ts.cell, rt = ts.row;
58879 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
58880 var hasListener = this.grid.hasListener('rowclass');
58883 for(var j = 0, len = rs.length; j < len; j++){
58884 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
58885 for(var i = 0; i < colCount; i++){
58887 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
58889 p.css = p.attr = "";
58890 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
58891 if(p.value == undefined || p.value === "") {
58892 p.value = " ";
58896 p.css += ' x-grid-editable-cell';
58898 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
58899 p.css += ' x-grid-dirty-cell'
58902 var markup = ct.apply(p);
58904 cb[cb.length] = markup;
58906 lcb[lcb.length] = markup;
58910 if(stripe && ((rowIndex+1) % 2 == 0)){
58911 alt.push( "x-grid-row-alt");
58914 alt.push(" x-grid-dirty-row");
58917 if(this.getRowClass){
58918 alt.push( this.getRowClass(r, rowIndex));
58924 rowIndex : rowIndex,
58927 this.grid.fireEvent('rowclass', this, rowcfg);
58928 alt.push(rowcfg.rowClass);
58931 rp.alt = alt.join(" ");
58932 rp.cells = lcb.join("");
58933 lbuf[lbuf.length] = rt.apply(rp);
58934 rp.cells = cb.join("");
58935 buf[buf.length] = rt.apply(rp);
58937 return [lbuf.join(""), buf.join("")];
58940 renderBody : function(){
58941 var markup = this.renderRows();
58942 var bt = this.templates.body;
58943 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
58947 * Refreshes the grid
58948 * @param {Boolean} headersToo
58950 refresh : function(headersToo){
58951 this.fireEvent("beforerefresh", this);
58952 this.grid.stopEditing();
58953 var result = this.renderBody();
58954 this.lockedBody.update(result[0]);
58955 this.mainBody.update(result[1]);
58956 if(headersToo === true){
58957 this.updateHeaders();
58958 this.updateColumns();
58959 this.updateSplitters();
58960 this.updateHeaderSortState();
58962 this.syncRowHeights();
58964 this.fireEvent("refresh", this);
58967 handleColumnMove : function(cm, oldIndex, newIndex){
58968 this.indexMap = null;
58969 var s = this.getScrollState();
58970 this.refresh(true);
58971 this.restoreScroll(s);
58972 this.afterMove(newIndex);
58975 afterMove : function(colIndex){
58976 if(this.enableMoveAnim && Roo.enableFx){
58977 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
58979 // if multisort - fix sortOrder, and reload..
58980 if (this.grid.dataSource.multiSort) {
58981 // the we can call sort again..
58982 var dm = this.grid.dataSource;
58983 var cm = this.grid.colModel;
58985 for(var i = 0; i < cm.config.length; i++ ) {
58987 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
58988 continue; // dont' bother, it's not in sort list or being set.
58991 so.push(cm.config[i].dataIndex);
58994 dm.load(dm.lastOptions);
59001 updateCell : function(dm, rowIndex, dataIndex){
59002 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
59003 if(typeof colIndex == "undefined"){ // not present in grid
59006 var cm = this.grid.colModel;
59007 var cell = this.getCell(rowIndex, colIndex);
59008 var cellText = this.getCellText(rowIndex, colIndex);
59011 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
59012 id : cm.getColumnId(colIndex),
59013 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
59015 var renderer = cm.getRenderer(colIndex);
59016 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
59017 if(typeof val == "undefined" || val === "") {
59020 cellText.innerHTML = val;
59021 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
59022 this.syncRowHeights(rowIndex, rowIndex);
59025 calcColumnWidth : function(colIndex, maxRowsToMeasure){
59027 if(this.grid.autoSizeHeaders){
59028 var h = this.getHeaderCellMeasure(colIndex);
59029 maxWidth = Math.max(maxWidth, h.scrollWidth);
59032 if(this.cm.isLocked(colIndex)){
59033 tb = this.getLockedTable();
59036 tb = this.getBodyTable();
59037 index = colIndex - this.cm.getLockedCount();
59040 var rows = tb.rows;
59041 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
59042 for(var i = 0; i < stopIndex; i++){
59043 var cell = rows[i].childNodes[index].firstChild;
59044 maxWidth = Math.max(maxWidth, cell.scrollWidth);
59047 return maxWidth + /*margin for error in IE*/ 5;
59050 * Autofit a column to its content.
59051 * @param {Number} colIndex
59052 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
59054 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
59055 if(this.cm.isHidden(colIndex)){
59056 return; // can't calc a hidden column
59059 var cid = this.cm.getColumnId(colIndex);
59060 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
59061 if(this.grid.autoSizeHeaders){
59062 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
59065 var newWidth = this.calcColumnWidth(colIndex);
59066 this.cm.setColumnWidth(colIndex,
59067 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
59068 if(!suppressEvent){
59069 this.grid.fireEvent("columnresize", colIndex, newWidth);
59074 * Autofits all columns to their content and then expands to fit any extra space in the grid
59076 autoSizeColumns : function(){
59077 var cm = this.grid.colModel;
59078 var colCount = cm.getColumnCount();
59079 for(var i = 0; i < colCount; i++){
59080 this.autoSizeColumn(i, true, true);
59082 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
59085 this.updateColumns();
59091 * Autofits all columns to the grid's width proportionate with their current size
59092 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
59094 fitColumns : function(reserveScrollSpace){
59095 var cm = this.grid.colModel;
59096 var colCount = cm.getColumnCount();
59100 for (i = 0; i < colCount; i++){
59101 if(!cm.isHidden(i) && !cm.isFixed(i)){
59102 w = cm.getColumnWidth(i);
59108 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
59109 if(reserveScrollSpace){
59112 var frac = (avail - cm.getTotalWidth())/width;
59113 while (cols.length){
59116 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
59118 this.updateColumns();
59122 onRowSelect : function(rowIndex){
59123 var row = this.getRowComposite(rowIndex);
59124 row.addClass("x-grid-row-selected");
59127 onRowDeselect : function(rowIndex){
59128 var row = this.getRowComposite(rowIndex);
59129 row.removeClass("x-grid-row-selected");
59132 onCellSelect : function(row, col){
59133 var cell = this.getCell(row, col);
59135 Roo.fly(cell).addClass("x-grid-cell-selected");
59139 onCellDeselect : function(row, col){
59140 var cell = this.getCell(row, col);
59142 Roo.fly(cell).removeClass("x-grid-cell-selected");
59146 updateHeaderSortState : function(){
59148 // sort state can be single { field: xxx, direction : yyy}
59149 // or { xxx=>ASC , yyy : DESC ..... }
59152 if (!this.ds.multiSort) {
59153 var state = this.ds.getSortState();
59157 mstate[state.field] = state.direction;
59158 // FIXME... - this is not used here.. but might be elsewhere..
59159 this.sortState = state;
59162 mstate = this.ds.sortToggle;
59164 //remove existing sort classes..
59166 var sc = this.sortClasses;
59167 var hds = this.el.select(this.headerSelector).removeClass(sc);
59169 for(var f in mstate) {
59171 var sortColumn = this.cm.findColumnIndex(f);
59173 if(sortColumn != -1){
59174 var sortDir = mstate[f];
59175 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
59184 handleHeaderClick : function(g, index,e){
59186 Roo.log("header click");
59189 // touch events on header are handled by context
59190 this.handleHdCtx(g,index,e);
59195 if(this.headersDisabled){
59198 var dm = g.dataSource, cm = g.colModel;
59199 if(!cm.isSortable(index)){
59204 if (dm.multiSort) {
59205 // update the sortOrder
59207 for(var i = 0; i < cm.config.length; i++ ) {
59209 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
59210 continue; // dont' bother, it's not in sort list or being set.
59213 so.push(cm.config[i].dataIndex);
59219 dm.sort(cm.getDataIndex(index));
59223 destroy : function(){
59225 this.colMenu.removeAll();
59226 Roo.menu.MenuMgr.unregister(this.colMenu);
59227 this.colMenu.getEl().remove();
59228 delete this.colMenu;
59231 this.hmenu.removeAll();
59232 Roo.menu.MenuMgr.unregister(this.hmenu);
59233 this.hmenu.getEl().remove();
59236 if(this.grid.enableColumnMove){
59237 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
59239 for(var dd in dds){
59240 if(!dds[dd].config.isTarget && dds[dd].dragElId){
59241 var elid = dds[dd].dragElId;
59243 Roo.get(elid).remove();
59244 } else if(dds[dd].config.isTarget){
59245 dds[dd].proxyTop.remove();
59246 dds[dd].proxyBottom.remove();
59249 if(Roo.dd.DDM.locationCache[dd]){
59250 delete Roo.dd.DDM.locationCache[dd];
59253 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
59256 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
59257 this.bind(null, null);
59258 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
59261 handleLockChange : function(){
59262 this.refresh(true);
59265 onDenyColumnLock : function(){
59269 onDenyColumnHide : function(){
59273 handleHdMenuClick : function(item){
59274 var index = this.hdCtxIndex;
59275 var cm = this.cm, ds = this.ds;
59278 ds.sort(cm.getDataIndex(index), "ASC");
59281 ds.sort(cm.getDataIndex(index), "DESC");
59284 var lc = cm.getLockedCount();
59285 if(cm.getColumnCount(true) <= lc+1){
59286 this.onDenyColumnLock();
59290 cm.setLocked(index, true, true);
59291 cm.moveColumn(index, lc);
59292 this.grid.fireEvent("columnmove", index, lc);
59294 cm.setLocked(index, true);
59298 var lc = cm.getLockedCount();
59299 if((lc-1) != index){
59300 cm.setLocked(index, false, true);
59301 cm.moveColumn(index, lc-1);
59302 this.grid.fireEvent("columnmove", index, lc-1);
59304 cm.setLocked(index, false);
59307 case 'wider': // used to expand cols on touch..
59309 var cw = cm.getColumnWidth(index);
59310 cw += (item.id == 'wider' ? 1 : -1) * 50;
59311 cw = Math.max(0, cw);
59312 cw = Math.min(cw,4000);
59313 cm.setColumnWidth(index, cw);
59317 index = cm.getIndexById(item.id.substr(4));
59319 if(item.checked && cm.getColumnCount(true) <= 1){
59320 this.onDenyColumnHide();
59323 cm.setHidden(index, item.checked);
59329 beforeColMenuShow : function(){
59330 var cm = this.cm, colCount = cm.getColumnCount();
59331 this.colMenu.removeAll();
59332 for(var i = 0; i < colCount; i++){
59333 this.colMenu.add(new Roo.menu.CheckItem({
59334 id: "col-"+cm.getColumnId(i),
59335 text: cm.getColumnHeader(i),
59336 checked: !cm.isHidden(i),
59342 handleHdCtx : function(g, index, e){
59344 var hd = this.getHeaderCell(index);
59345 this.hdCtxIndex = index;
59346 var ms = this.hmenu.items, cm = this.cm;
59347 ms.get("asc").setDisabled(!cm.isSortable(index));
59348 ms.get("desc").setDisabled(!cm.isSortable(index));
59349 if(this.grid.enableColLock !== false){
59350 ms.get("lock").setDisabled(cm.isLocked(index));
59351 ms.get("unlock").setDisabled(!cm.isLocked(index));
59353 this.hmenu.show(hd, "tl-bl");
59356 handleHdOver : function(e){
59357 var hd = this.findHeaderCell(e.getTarget());
59358 if(hd && !this.headersDisabled){
59359 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
59360 this.fly(hd).addClass("x-grid-hd-over");
59365 handleHdOut : function(e){
59366 var hd = this.findHeaderCell(e.getTarget());
59368 this.fly(hd).removeClass("x-grid-hd-over");
59372 handleSplitDblClick : function(e, t){
59373 var i = this.getCellIndex(t);
59374 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
59375 this.autoSizeColumn(i, true);
59380 render : function(){
59383 var colCount = cm.getColumnCount();
59385 if(this.grid.monitorWindowResize === true){
59386 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
59388 var header = this.renderHeaders();
59389 var body = this.templates.body.apply({rows:""});
59390 var html = this.templates.master.apply({
59393 lockedHeader: header[0],
59397 //this.updateColumns();
59399 this.grid.getGridEl().dom.innerHTML = html;
59401 this.initElements();
59403 // a kludge to fix the random scolling effect in webkit
59404 this.el.on("scroll", function() {
59405 this.el.dom.scrollTop=0; // hopefully not recursive..
59408 this.scroller.on("scroll", this.handleScroll, this);
59409 this.lockedBody.on("mousewheel", this.handleWheel, this);
59410 this.mainBody.on("mousewheel", this.handleWheel, this);
59412 this.mainHd.on("mouseover", this.handleHdOver, this);
59413 this.mainHd.on("mouseout", this.handleHdOut, this);
59414 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
59415 {delegate: "."+this.splitClass});
59417 this.lockedHd.on("mouseover", this.handleHdOver, this);
59418 this.lockedHd.on("mouseout", this.handleHdOut, this);
59419 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
59420 {delegate: "."+this.splitClass});
59422 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
59423 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
59426 this.updateSplitters();
59428 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
59429 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
59430 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
59433 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
59434 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
59436 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
59437 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
59439 if(this.grid.enableColLock !== false){
59440 this.hmenu.add('-',
59441 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
59442 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
59446 this.hmenu.add('-',
59447 {id:"wider", text: this.columnsWiderText},
59448 {id:"narrow", text: this.columnsNarrowText }
59454 if(this.grid.enableColumnHide !== false){
59456 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
59457 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
59458 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
59460 this.hmenu.add('-',
59461 {id:"columns", text: this.columnsText, menu: this.colMenu}
59464 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
59466 this.grid.on("headercontextmenu", this.handleHdCtx, this);
59469 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
59470 this.dd = new Roo.grid.GridDragZone(this.grid, {
59471 ddGroup : this.grid.ddGroup || 'GridDD'
59477 for(var i = 0; i < colCount; i++){
59478 if(cm.isHidden(i)){
59479 this.hideColumn(i);
59481 if(cm.config[i].align){
59482 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
59483 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
59487 this.updateHeaderSortState();
59489 this.beforeInitialResize();
59492 // two part rendering gives faster view to the user
59493 this.renderPhase2.defer(1, this);
59496 renderPhase2 : function(){
59497 // render the rows now
59499 if(this.grid.autoSizeColumns){
59500 this.autoSizeColumns();
59504 beforeInitialResize : function(){
59508 onColumnSplitterMoved : function(i, w){
59509 this.userResized = true;
59510 var cm = this.grid.colModel;
59511 cm.setColumnWidth(i, w, true);
59512 var cid = cm.getColumnId(i);
59513 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
59514 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
59515 this.updateSplitters();
59517 this.grid.fireEvent("columnresize", i, w);
59520 syncRowHeights : function(startIndex, endIndex){
59521 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
59522 startIndex = startIndex || 0;
59523 var mrows = this.getBodyTable().rows;
59524 var lrows = this.getLockedTable().rows;
59525 var len = mrows.length-1;
59526 endIndex = Math.min(endIndex || len, len);
59527 for(var i = startIndex; i <= endIndex; i++){
59528 var m = mrows[i], l = lrows[i];
59529 var h = Math.max(m.offsetHeight, l.offsetHeight);
59530 m.style.height = l.style.height = h + "px";
59535 layout : function(initialRender, is2ndPass)
59538 var auto = g.autoHeight;
59539 var scrollOffset = 16;
59540 var c = g.getGridEl(), cm = this.cm,
59541 expandCol = g.autoExpandColumn,
59543 //c.beginMeasure();
59545 if(!c.dom.offsetWidth){ // display:none?
59547 this.lockedWrap.show();
59548 this.mainWrap.show();
59553 var hasLock = this.cm.isLocked(0);
59555 var tbh = this.headerPanel.getHeight();
59556 var bbh = this.footerPanel.getHeight();
59559 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
59560 var newHeight = ch + c.getBorderWidth("tb");
59562 newHeight = Math.min(g.maxHeight, newHeight);
59564 c.setHeight(newHeight);
59568 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
59571 var s = this.scroller;
59573 var csize = c.getSize(true);
59575 this.el.setSize(csize.width, csize.height);
59577 this.headerPanel.setWidth(csize.width);
59578 this.footerPanel.setWidth(csize.width);
59580 var hdHeight = this.mainHd.getHeight();
59581 var vw = csize.width;
59582 var vh = csize.height - (tbh + bbh);
59586 var bt = this.getBodyTable();
59588 if(cm.getLockedCount() == cm.config.length){
59589 bt = this.getLockedTable();
59592 var ltWidth = hasLock ?
59593 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
59595 var scrollHeight = bt.offsetHeight;
59596 var scrollWidth = ltWidth + bt.offsetWidth;
59597 var vscroll = false, hscroll = false;
59599 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
59601 var lw = this.lockedWrap, mw = this.mainWrap;
59602 var lb = this.lockedBody, mb = this.mainBody;
59604 setTimeout(function(){
59605 var t = s.dom.offsetTop;
59606 var w = s.dom.clientWidth,
59607 h = s.dom.clientHeight;
59610 lw.setSize(ltWidth, h);
59612 mw.setLeftTop(ltWidth, t);
59613 mw.setSize(w-ltWidth, h);
59615 lb.setHeight(h-hdHeight);
59616 mb.setHeight(h-hdHeight);
59618 if(is2ndPass !== true && !gv.userResized && expandCol){
59619 // high speed resize without full column calculation
59621 var ci = cm.getIndexById(expandCol);
59623 ci = cm.findColumnIndex(expandCol);
59625 ci = Math.max(0, ci); // make sure it's got at least the first col.
59626 var expandId = cm.getColumnId(ci);
59627 var tw = cm.getTotalWidth(false);
59628 var currentWidth = cm.getColumnWidth(ci);
59629 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
59630 if(currentWidth != cw){
59631 cm.setColumnWidth(ci, cw, true);
59632 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
59633 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
59634 gv.updateSplitters();
59635 gv.layout(false, true);
59647 onWindowResize : function(){
59648 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
59654 appendFooter : function(parentEl){
59658 sortAscText : "Sort Ascending",
59659 sortDescText : "Sort Descending",
59660 lockText : "Lock Column",
59661 unlockText : "Unlock Column",
59662 columnsText : "Columns",
59664 columnsWiderText : "Wider",
59665 columnsNarrowText : "Thinner"
59669 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
59670 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
59671 this.proxy.el.addClass('x-grid3-col-dd');
59674 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
59675 handleMouseDown : function(e){
59679 callHandleMouseDown : function(e){
59680 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
59685 * Ext JS Library 1.1.1
59686 * Copyright(c) 2006-2007, Ext JS, LLC.
59688 * Originally Released Under LGPL - original licence link has changed is not relivant.
59691 * <script type="text/javascript">
59694 * @extends Roo.dd.DDProxy
59695 * @class Roo.grid.SplitDragZone
59696 * Support for Column Header resizing
59698 * @param {Object} config
59701 // This is a support class used internally by the Grid components
59702 Roo.grid.SplitDragZone = function(grid, hd, hd2){
59704 this.view = grid.getView();
59705 this.proxy = this.view.resizeProxy;
59706 Roo.grid.SplitDragZone.superclass.constructor.call(
59709 "gridSplitters" + this.grid.getGridEl().id, // SGROUP
59711 dragElId : Roo.id(this.proxy.dom),
59716 this.setHandleElId(Roo.id(hd));
59717 if (hd2 !== false) {
59718 this.setOuterHandleElId(Roo.id(hd2));
59721 this.scroll = false;
59723 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
59724 fly: Roo.Element.fly,
59726 b4StartDrag : function(x, y){
59727 this.view.headersDisabled = true;
59728 var h = this.view.mainWrap ? this.view.mainWrap.getHeight() : (
59729 this.view.headEl.getHeight() + this.view.bodyEl.getHeight()
59731 this.proxy.setHeight(h);
59733 // for old system colWidth really stored the actual width?
59734 // in bootstrap we tried using xs/ms/etc.. to do % sizing?
59735 // which in reality did not work.. - it worked only for fixed sizes
59736 // for resizable we need to use actual sizes.
59737 var w = this.cm.getColumnWidth(this.cellIndex);
59738 if (!this.view.mainWrap) {
59740 w = this.view.getHeaderIndex(this.cellIndex).getWidth();
59745 // this was w-this.grid.minColumnWidth;
59746 // doesnt really make sense? - w = thie curren width or the rendered one?
59747 var minw = Math.max(w-this.grid.minColumnWidth, 0);
59748 this.resetConstraints();
59749 this.setXConstraint(minw, 1000);
59750 this.setYConstraint(0, 0);
59751 this.minX = x - minw;
59752 this.maxX = x + 1000;
59754 if (!this.view.mainWrap) { // this is Bootstrap code..
59755 this.getDragEl().style.display='block';
59758 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
59762 handleMouseDown : function(e){
59763 ev = Roo.EventObject.setEvent(e);
59764 var t = this.fly(ev.getTarget());
59765 if(t.hasClass("x-grid-split")){
59766 this.cellIndex = this.view.getCellIndex(t.dom);
59767 this.split = t.dom;
59768 this.cm = this.grid.colModel;
59769 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
59770 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
59775 endDrag : function(e){
59776 this.view.headersDisabled = false;
59777 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
59778 var diff = endX - this.startPos;
59780 var w = this.cm.getColumnWidth(this.cellIndex);
59781 if (!this.view.mainWrap) {
59784 this.view.onColumnSplitterMoved(this.cellIndex, w+diff);
59787 autoOffset : function(){
59788 this.setDelta(0,0);
59792 * Ext JS Library 1.1.1
59793 * Copyright(c) 2006-2007, Ext JS, LLC.
59795 * Originally Released Under LGPL - original licence link has changed is not relivant.
59798 * <script type="text/javascript">
59802 // This is a support class used internally by the Grid components
59803 Roo.grid.GridDragZone = function(grid, config){
59804 this.view = grid.getView();
59805 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
59806 if(this.view.lockedBody){
59807 this.setHandleElId(Roo.id(this.view.mainBody.dom));
59808 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
59810 this.scroll = false;
59812 this.ddel = document.createElement('div');
59813 this.ddel.className = 'x-grid-dd-wrap';
59816 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
59817 ddGroup : "GridDD",
59819 getDragData : function(e){
59820 var t = Roo.lib.Event.getTarget(e);
59821 var rowIndex = this.view.findRowIndex(t);
59822 var sm = this.grid.selModel;
59824 //Roo.log(rowIndex);
59826 if (sm.getSelectedCell) {
59827 // cell selection..
59828 if (!sm.getSelectedCell()) {
59831 if (rowIndex != sm.getSelectedCell()[0]) {
59836 if (sm.getSelections && sm.getSelections().length < 1) {
59841 // before it used to all dragging of unseleted... - now we dont do that.
59842 if(rowIndex !== false){
59847 //Roo.log([ sm.getSelectedCell() ? sm.getSelectedCell()[0] : 'NO' , rowIndex ]);
59849 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
59852 if (e.hasModifier()){
59853 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
59856 Roo.log("getDragData");
59861 rowIndex: rowIndex,
59862 selections: sm.getSelections ? sm.getSelections() : (
59863 sm.getSelectedCell() ? [ this.grid.ds.getAt(sm.getSelectedCell()[0]) ] : [])
59870 onInitDrag : function(e){
59871 var data = this.dragData;
59872 this.ddel.innerHTML = this.grid.getDragDropText();
59873 this.proxy.update(this.ddel);
59874 // fire start drag?
59877 afterRepair : function(){
59878 this.dragging = false;
59881 getRepairXY : function(e, data){
59885 onEndDrag : function(data, e){
59889 onValidDrop : function(dd, e, id){
59894 beforeInvalidDrop : function(e, id){
59899 * Ext JS Library 1.1.1
59900 * Copyright(c) 2006-2007, Ext JS, LLC.
59902 * Originally Released Under LGPL - original licence link has changed is not relivant.
59905 * <script type="text/javascript">
59910 * @class Roo.grid.ColumnModel
59911 * @extends Roo.util.Observable
59912 * This is the default implementation of a ColumnModel used by the Grid. It defines
59913 * the columns in the grid.
59916 var colModel = new Roo.grid.ColumnModel([
59917 {header: "Ticker", width: 60, sortable: true, locked: true},
59918 {header: "Company Name", width: 150, sortable: true},
59919 {header: "Market Cap.", width: 100, sortable: true},
59920 {header: "$ Sales", width: 100, sortable: true, renderer: money},
59921 {header: "Employees", width: 100, sortable: true, resizable: false}
59926 * The config options listed for this class are options which may appear in each
59927 * individual column definition.
59928 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
59930 * @param {Object} config An Array of column config objects. See this class's
59931 * config objects for details.
59933 Roo.grid.ColumnModel = function(config){
59935 * The config passed into the constructor
59937 this.config = []; //config;
59940 // if no id, create one
59941 // if the column does not have a dataIndex mapping,
59942 // map it to the order it is in the config
59943 for(var i = 0, len = config.length; i < len; i++){
59944 this.addColumn(config[i]);
59949 * The width of columns which have no width specified (defaults to 100)
59952 this.defaultWidth = 100;
59955 * Default sortable of columns which have no sortable specified (defaults to false)
59958 this.defaultSortable = false;
59962 * @event widthchange
59963 * Fires when the width of a column changes.
59964 * @param {ColumnModel} this
59965 * @param {Number} columnIndex The column index
59966 * @param {Number} newWidth The new width
59968 "widthchange": true,
59970 * @event headerchange
59971 * Fires when the text of a header changes.
59972 * @param {ColumnModel} this
59973 * @param {Number} columnIndex The column index
59974 * @param {Number} newText The new header text
59976 "headerchange": true,
59978 * @event hiddenchange
59979 * Fires when a column is hidden or "unhidden".
59980 * @param {ColumnModel} this
59981 * @param {Number} columnIndex The column index
59982 * @param {Boolean} hidden true if hidden, false otherwise
59984 "hiddenchange": true,
59986 * @event columnmoved
59987 * Fires when a column is moved.
59988 * @param {ColumnModel} this
59989 * @param {Number} oldIndex
59990 * @param {Number} newIndex
59992 "columnmoved" : true,
59994 * @event columlockchange
59995 * Fires when a column's locked state is changed
59996 * @param {ColumnModel} this
59997 * @param {Number} colIndex
59998 * @param {Boolean} locked true if locked
60000 "columnlockchange" : true
60002 Roo.grid.ColumnModel.superclass.constructor.call(this);
60004 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
60006 * @cfg {String} header The header text to display in the Grid view.
60009 * @cfg {String} xsHeader Header at Bootsrap Extra Small width (default for all)
60012 * @cfg {String} smHeader Header at Bootsrap Small width
60015 * @cfg {String} mdHeader Header at Bootsrap Medium width
60018 * @cfg {String} lgHeader Header at Bootsrap Large width
60021 * @cfg {String} xlHeader Header at Bootsrap extra Large width
60024 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
60025 * {@link Roo.data.Record} definition from which to draw the column's value. If not
60026 * specified, the column's index is used as an index into the Record's data Array.
60029 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
60030 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
60033 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
60034 * Defaults to the value of the {@link #defaultSortable} property.
60035 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
60038 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
60041 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
60044 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
60047 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
60050 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
60051 * given the cell's data value. See {@link #setRenderer}. If not specified, the
60052 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
60053 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
60056 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
60059 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
60062 * @cfg {String} valign (Optional) Set the CSS vertical-align property of the column (eg. middle, top, bottom etc). Defaults to undefined.
60065 * @cfg {String} cursor (Optional)
60068 * @cfg {String} tooltip (Optional)
60071 * @cfg {Number} xs (Optional) can be '0' for hidden at this size (number less than 12)
60074 * @cfg {Number} sm (Optional) can be '0' for hidden at this size (number less than 12)
60077 * @cfg {Number} md (Optional) can be '0' for hidden at this size (number less than 12)
60080 * @cfg {Number} lg (Optional) can be '0' for hidden at this size (number less than 12)
60083 * @cfg {Number} xl (Optional) can be '0' for hidden at this size (number less than 12)
60086 * Returns the id of the column at the specified index.
60087 * @param {Number} index The column index
60088 * @return {String} the id
60090 getColumnId : function(index){
60091 return this.config[index].id;
60095 * Returns the column for a specified id.
60096 * @param {String} id The column id
60097 * @return {Object} the column
60099 getColumnById : function(id){
60100 return this.lookup[id];
60105 * Returns the column Object for a specified dataIndex.
60106 * @param {String} dataIndex The column dataIndex
60107 * @return {Object|Boolean} the column or false if not found
60109 getColumnByDataIndex: function(dataIndex){
60110 var index = this.findColumnIndex(dataIndex);
60111 return index > -1 ? this.config[index] : false;
60115 * Returns the index for a specified column id.
60116 * @param {String} id The column id
60117 * @return {Number} the index, or -1 if not found
60119 getIndexById : function(id){
60120 for(var i = 0, len = this.config.length; i < len; i++){
60121 if(this.config[i].id == id){
60129 * Returns the index for a specified column dataIndex.
60130 * @param {String} dataIndex The column dataIndex
60131 * @return {Number} the index, or -1 if not found
60134 findColumnIndex : function(dataIndex){
60135 for(var i = 0, len = this.config.length; i < len; i++){
60136 if(this.config[i].dataIndex == dataIndex){
60144 moveColumn : function(oldIndex, newIndex){
60145 var c = this.config[oldIndex];
60146 this.config.splice(oldIndex, 1);
60147 this.config.splice(newIndex, 0, c);
60148 this.dataMap = null;
60149 this.fireEvent("columnmoved", this, oldIndex, newIndex);
60152 isLocked : function(colIndex){
60153 return this.config[colIndex].locked === true;
60156 setLocked : function(colIndex, value, suppressEvent){
60157 if(this.isLocked(colIndex) == value){
60160 this.config[colIndex].locked = value;
60161 if(!suppressEvent){
60162 this.fireEvent("columnlockchange", this, colIndex, value);
60166 getTotalLockedWidth : function(){
60167 var totalWidth = 0;
60168 for(var i = 0; i < this.config.length; i++){
60169 if(this.isLocked(i) && !this.isHidden(i)){
60170 this.totalWidth += this.getColumnWidth(i);
60176 getLockedCount : function(){
60177 for(var i = 0, len = this.config.length; i < len; i++){
60178 if(!this.isLocked(i)){
60183 return this.config.length;
60187 * Returns the number of columns.
60190 getColumnCount : function(visibleOnly){
60191 if(visibleOnly === true){
60193 for(var i = 0, len = this.config.length; i < len; i++){
60194 if(!this.isHidden(i)){
60200 return this.config.length;
60204 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
60205 * @param {Function} fn
60206 * @param {Object} scope (optional)
60207 * @return {Array} result
60209 getColumnsBy : function(fn, scope){
60211 for(var i = 0, len = this.config.length; i < len; i++){
60212 var c = this.config[i];
60213 if(fn.call(scope||this, c, i) === true){
60221 * Returns true if the specified column is sortable.
60222 * @param {Number} col The column index
60223 * @return {Boolean}
60225 isSortable : function(col){
60226 if(typeof this.config[col].sortable == "undefined"){
60227 return this.defaultSortable;
60229 return this.config[col].sortable;
60233 * Returns the rendering (formatting) function defined for the column.
60234 * @param {Number} col The column index.
60235 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
60237 getRenderer : function(col){
60238 if(!this.config[col].renderer){
60239 return Roo.grid.ColumnModel.defaultRenderer;
60241 return this.config[col].renderer;
60245 * Sets the rendering (formatting) function for a column.
60246 * @param {Number} col The column index
60247 * @param {Function} fn The function to use to process the cell's raw data
60248 * to return HTML markup for the grid view. The render function is called with
60249 * the following parameters:<ul>
60250 * <li>Data value.</li>
60251 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
60252 * <li>css A CSS style string to apply to the table cell.</li>
60253 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
60254 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
60255 * <li>Row index</li>
60256 * <li>Column index</li>
60257 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
60259 setRenderer : function(col, fn){
60260 this.config[col].renderer = fn;
60264 * Returns the width for the specified column.
60265 * @param {Number} col The column index
60266 * @param (optional) {String} gridSize bootstrap width size.
60269 getColumnWidth : function(col, gridSize)
60271 var cfg = this.config[col];
60273 if (typeof(gridSize) == 'undefined') {
60274 return cfg.width * 1 || this.defaultWidth;
60276 if (gridSize === false) { // if we set it..
60277 return cfg.width || false;
60279 var sizes = ['xl', 'lg', 'md', 'sm', 'xs'];
60281 for(var i = sizes.indexOf(gridSize); i < sizes.length; i++) {
60282 if (typeof(cfg[ sizes[i] ] ) == 'undefined') {
60285 return cfg[ sizes[i] ];
60292 * Sets the width for a column.
60293 * @param {Number} col The column index
60294 * @param {Number} width The new width
60296 setColumnWidth : function(col, width, suppressEvent){
60297 this.config[col].width = width;
60298 this.totalWidth = null;
60299 if(!suppressEvent){
60300 this.fireEvent("widthchange", this, col, width);
60305 * Returns the total width of all columns.
60306 * @param {Boolean} includeHidden True to include hidden column widths
60309 getTotalWidth : function(includeHidden){
60310 if(!this.totalWidth){
60311 this.totalWidth = 0;
60312 for(var i = 0, len = this.config.length; i < len; i++){
60313 if(includeHidden || !this.isHidden(i)){
60314 this.totalWidth += this.getColumnWidth(i);
60318 return this.totalWidth;
60322 * Returns the header for the specified column.
60323 * @param {Number} col The column index
60326 getColumnHeader : function(col){
60327 return this.config[col].header;
60331 * Sets the header for a column.
60332 * @param {Number} col The column index
60333 * @param {String} header The new header
60335 setColumnHeader : function(col, header){
60336 this.config[col].header = header;
60337 this.fireEvent("headerchange", this, col, header);
60341 * Returns the tooltip for the specified column.
60342 * @param {Number} col The column index
60345 getColumnTooltip : function(col){
60346 return this.config[col].tooltip;
60349 * Sets the tooltip for a column.
60350 * @param {Number} col The column index
60351 * @param {String} tooltip The new tooltip
60353 setColumnTooltip : function(col, tooltip){
60354 this.config[col].tooltip = tooltip;
60358 * Returns the dataIndex for the specified column.
60359 * @param {Number} col The column index
60362 getDataIndex : function(col){
60363 return this.config[col].dataIndex;
60367 * Sets the dataIndex for a column.
60368 * @param {Number} col The column index
60369 * @param {Number} dataIndex The new dataIndex
60371 setDataIndex : function(col, dataIndex){
60372 this.config[col].dataIndex = dataIndex;
60378 * Returns true if the cell is editable.
60379 * @param {Number} colIndex The column index
60380 * @param {Number} rowIndex The row index - this is nto actually used..?
60381 * @return {Boolean}
60383 isCellEditable : function(colIndex, rowIndex){
60384 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
60388 * Returns the editor defined for the cell/column.
60389 * return false or null to disable editing.
60390 * @param {Number} colIndex The column index
60391 * @param {Number} rowIndex The row index
60394 getCellEditor : function(colIndex, rowIndex){
60395 return this.config[colIndex].editor;
60399 * Sets if a column is editable.
60400 * @param {Number} col The column index
60401 * @param {Boolean} editable True if the column is editable
60403 setEditable : function(col, editable){
60404 this.config[col].editable = editable;
60409 * Returns true if the column is hidden.
60410 * @param {Number} colIndex The column index
60411 * @return {Boolean}
60413 isHidden : function(colIndex){
60414 return this.config[colIndex].hidden;
60419 * Returns true if the column width cannot be changed
60421 isFixed : function(colIndex){
60422 return this.config[colIndex].fixed;
60426 * Returns true if the column can be resized
60427 * @return {Boolean}
60429 isResizable : function(colIndex){
60430 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
60433 * Sets if a column is hidden.
60434 * @param {Number} colIndex The column index
60435 * @param {Boolean} hidden True if the column is hidden
60437 setHidden : function(colIndex, hidden){
60438 this.config[colIndex].hidden = hidden;
60439 this.totalWidth = null;
60440 this.fireEvent("hiddenchange", this, colIndex, hidden);
60444 * Sets the editor for a column.
60445 * @param {Number} col The column index
60446 * @param {Object} editor The editor object
60448 setEditor : function(col, editor){
60449 this.config[col].editor = editor;
60452 * Add a column (experimental...) - defaults to adding to the end..
60453 * @param {Object} config
60455 addColumn : function(c)
60458 var i = this.config.length;
60459 this.config[i] = c;
60461 if(typeof c.dataIndex == "undefined"){
60464 if(typeof c.renderer == "string"){
60465 c.renderer = Roo.util.Format[c.renderer];
60467 if(typeof c.id == "undefined"){
60470 if(c.editor && c.editor.xtype){
60471 c.editor = Roo.factory(c.editor, Roo.grid);
60473 if(c.editor && c.editor.isFormField){
60474 c.editor = new Roo.grid.GridEditor(c.editor);
60476 this.lookup[c.id] = c;
60481 Roo.grid.ColumnModel.defaultRenderer = function(value)
60483 if(typeof value == "object") {
60486 if(typeof value == "string" && value.length < 1){
60490 return String.format("{0}", value);
60493 // Alias for backwards compatibility
60494 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
60497 * Ext JS Library 1.1.1
60498 * Copyright(c) 2006-2007, Ext JS, LLC.
60500 * Originally Released Under LGPL - original licence link has changed is not relivant.
60503 * <script type="text/javascript">
60507 * @class Roo.grid.AbstractSelectionModel
60508 * @extends Roo.util.Observable
60510 * Abstract base class for grid SelectionModels. It provides the interface that should be
60511 * implemented by descendant classes. This class should not be directly instantiated.
60514 Roo.grid.AbstractSelectionModel = function(){
60515 this.locked = false;
60516 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
60519 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
60520 /** @ignore Called by the grid automatically. Do not call directly. */
60521 init : function(grid){
60527 * Locks the selections.
60530 this.locked = true;
60534 * Unlocks the selections.
60536 unlock : function(){
60537 this.locked = false;
60541 * Returns true if the selections are locked.
60542 * @return {Boolean}
60544 isLocked : function(){
60545 return this.locked;
60549 * Ext JS Library 1.1.1
60550 * Copyright(c) 2006-2007, Ext JS, LLC.
60552 * Originally Released Under LGPL - original licence link has changed is not relivant.
60555 * <script type="text/javascript">
60558 * @extends Roo.grid.AbstractSelectionModel
60559 * @class Roo.grid.RowSelectionModel
60560 * The default SelectionModel used by {@link Roo.grid.Grid}.
60561 * It supports multiple selections and keyboard selection/navigation.
60563 * @param {Object} config
60565 Roo.grid.RowSelectionModel = function(config){
60566 Roo.apply(this, config);
60567 this.selections = new Roo.util.MixedCollection(false, function(o){
60572 this.lastActive = false;
60576 * @event selectionchange
60577 * Fires when the selection changes
60578 * @param {SelectionModel} this
60580 "selectionchange" : true,
60582 * @event afterselectionchange
60583 * Fires after the selection changes (eg. by key press or clicking)
60584 * @param {SelectionModel} this
60586 "afterselectionchange" : true,
60588 * @event beforerowselect
60589 * Fires when a row is selected being selected, return false to cancel.
60590 * @param {SelectionModel} this
60591 * @param {Number} rowIndex The selected index
60592 * @param {Boolean} keepExisting False if other selections will be cleared
60594 "beforerowselect" : true,
60597 * Fires when a row is selected.
60598 * @param {SelectionModel} this
60599 * @param {Number} rowIndex The selected index
60600 * @param {Roo.data.Record} r The record
60602 "rowselect" : true,
60604 * @event rowdeselect
60605 * Fires when a row is deselected.
60606 * @param {SelectionModel} this
60607 * @param {Number} rowIndex The selected index
60609 "rowdeselect" : true
60611 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
60612 this.locked = false;
60615 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
60617 * @cfg {Boolean} singleSelect
60618 * True to allow selection of only one row at a time (defaults to false)
60620 singleSelect : false,
60623 initEvents : function(){
60625 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
60626 this.grid.on("mousedown", this.handleMouseDown, this);
60627 }else{ // allow click to work like normal
60628 this.grid.on("rowclick", this.handleDragableRowClick, this);
60630 // bootstrap does not have a view..
60631 var view = this.grid.view ? this.grid.view : this.grid;
60632 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
60633 "up" : function(e){
60635 this.selectPrevious(e.shiftKey);
60636 }else if(this.last !== false && this.lastActive !== false){
60637 var last = this.last;
60638 this.selectRange(this.last, this.lastActive-1);
60639 view.focusRow(this.lastActive);
60640 if(last !== false){
60644 this.selectFirstRow();
60646 this.fireEvent("afterselectionchange", this);
60648 "down" : function(e){
60650 this.selectNext(e.shiftKey);
60651 }else if(this.last !== false && this.lastActive !== false){
60652 var last = this.last;
60653 this.selectRange(this.last, this.lastActive+1);
60654 view.focusRow(this.lastActive);
60655 if(last !== false){
60659 this.selectFirstRow();
60661 this.fireEvent("afterselectionchange", this);
60667 view.on("refresh", this.onRefresh, this);
60668 view.on("rowupdated", this.onRowUpdated, this);
60669 view.on("rowremoved", this.onRemove, this);
60673 onRefresh : function(){
60674 var ds = this.grid.ds, i, v = this.grid.view;
60675 var s = this.selections;
60676 s.each(function(r){
60677 if((i = ds.indexOfId(r.id)) != -1){
60679 s.add(ds.getAt(i)); // updating the selection relate data
60687 onRemove : function(v, index, r){
60688 this.selections.remove(r);
60692 onRowUpdated : function(v, index, r){
60693 if(this.isSelected(r)){
60694 v.onRowSelect(index);
60700 * @param {Array} records The records to select
60701 * @param {Boolean} keepExisting (optional) True to keep existing selections
60703 selectRecords : function(records, keepExisting){
60705 this.clearSelections();
60707 var ds = this.grid.ds;
60708 for(var i = 0, len = records.length; i < len; i++){
60709 this.selectRow(ds.indexOf(records[i]), true);
60714 * Gets the number of selected rows.
60717 getCount : function(){
60718 return this.selections.length;
60722 * Selects the first row in the grid.
60724 selectFirstRow : function(){
60729 * Select the last row.
60730 * @param {Boolean} keepExisting (optional) True to keep existing selections
60732 selectLastRow : function(keepExisting){
60733 this.selectRow(this.grid.ds.getCount() - 1, keepExisting);
60737 * Selects the row immediately following the last selected row.
60738 * @param {Boolean} keepExisting (optional) True to keep existing selections
60740 selectNext : function(keepExisting){
60741 if(this.last !== false && (this.last+1) < this.grid.ds.getCount()){
60742 this.selectRow(this.last+1, keepExisting);
60743 var view = this.grid.view ? this.grid.view : this.grid;
60744 view.focusRow(this.last);
60749 * Selects the row that precedes the last selected row.
60750 * @param {Boolean} keepExisting (optional) True to keep existing selections
60752 selectPrevious : function(keepExisting){
60754 this.selectRow(this.last-1, keepExisting);
60755 var view = this.grid.view ? this.grid.view : this.grid;
60756 view.focusRow(this.last);
60761 * Returns the selected records
60762 * @return {Array} Array of selected records
60764 getSelections : function(){
60765 return [].concat(this.selections.items);
60769 * Returns the first selected record.
60772 getSelected : function(){
60773 return this.selections.itemAt(0);
60778 * Clears all selections.
60780 clearSelections : function(fast){
60785 var ds = this.grid.ds;
60786 var s = this.selections;
60787 s.each(function(r){
60788 this.deselectRow(ds.indexOfId(r.id));
60792 this.selections.clear();
60799 * Selects all rows.
60801 selectAll : function(){
60805 this.selections.clear();
60806 for(var i = 0, len = this.grid.ds.getCount(); i < len; i++){
60807 this.selectRow(i, true);
60812 * Returns True if there is a selection.
60813 * @return {Boolean}
60815 hasSelection : function(){
60816 return this.selections.length > 0;
60820 * Returns True if the specified row is selected.
60821 * @param {Number/Record} record The record or index of the record to check
60822 * @return {Boolean}
60824 isSelected : function(index){
60825 var r = typeof index == "number" ? this.grid.ds.getAt(index) : index;
60826 return (r && this.selections.key(r.id) ? true : false);
60830 * Returns True if the specified record id is selected.
60831 * @param {String} id The id of record to check
60832 * @return {Boolean}
60834 isIdSelected : function(id){
60835 return (this.selections.key(id) ? true : false);
60839 handleMouseDown : function(e, t)
60841 var view = this.grid.view ? this.grid.view : this.grid;
60843 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
60846 if(e.shiftKey && this.last !== false){
60847 var last = this.last;
60848 this.selectRange(last, rowIndex, e.ctrlKey);
60849 this.last = last; // reset the last
60850 view.focusRow(rowIndex);
60852 var isSelected = this.isSelected(rowIndex);
60853 if(e.button !== 0 && isSelected){
60854 view.focusRow(rowIndex);
60855 }else if(e.ctrlKey && isSelected){
60856 this.deselectRow(rowIndex);
60857 }else if(!isSelected){
60858 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
60859 view.focusRow(rowIndex);
60862 this.fireEvent("afterselectionchange", this);
60865 handleDragableRowClick : function(grid, rowIndex, e)
60867 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
60868 this.selectRow(rowIndex, false);
60869 var view = this.grid.view ? this.grid.view : this.grid;
60870 view.focusRow(rowIndex);
60871 this.fireEvent("afterselectionchange", this);
60876 * Selects multiple rows.
60877 * @param {Array} rows Array of the indexes of the row to select
60878 * @param {Boolean} keepExisting (optional) True to keep existing selections
60880 selectRows : function(rows, keepExisting){
60882 this.clearSelections();
60884 for(var i = 0, len = rows.length; i < len; i++){
60885 this.selectRow(rows[i], true);
60890 * Selects a range of rows. All rows in between startRow and endRow are also selected.
60891 * @param {Number} startRow The index of the first row in the range
60892 * @param {Number} endRow The index of the last row in the range
60893 * @param {Boolean} keepExisting (optional) True to retain existing selections
60895 selectRange : function(startRow, endRow, keepExisting){
60900 this.clearSelections();
60902 if(startRow <= endRow){
60903 for(var i = startRow; i <= endRow; i++){
60904 this.selectRow(i, true);
60907 for(var i = startRow; i >= endRow; i--){
60908 this.selectRow(i, true);
60914 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
60915 * @param {Number} startRow The index of the first row in the range
60916 * @param {Number} endRow The index of the last row in the range
60918 deselectRange : function(startRow, endRow, preventViewNotify){
60922 for(var i = startRow; i <= endRow; i++){
60923 this.deselectRow(i, preventViewNotify);
60929 * @param {Number} row The index of the row to select
60930 * @param {Boolean} keepExisting (optional) True to keep existing selections
60932 selectRow : function(index, keepExisting, preventViewNotify){
60933 if(this.locked || (index < 0 || index >= this.grid.ds.getCount())) {
60936 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
60937 if(!keepExisting || this.singleSelect){
60938 this.clearSelections();
60940 var r = this.grid.ds.getAt(index);
60941 this.selections.add(r);
60942 this.last = this.lastActive = index;
60943 if(!preventViewNotify){
60944 var view = this.grid.view ? this.grid.view : this.grid;
60945 view.onRowSelect(index);
60947 this.fireEvent("rowselect", this, index, r);
60948 this.fireEvent("selectionchange", this);
60954 * @param {Number} row The index of the row to deselect
60956 deselectRow : function(index, preventViewNotify){
60960 if(this.last == index){
60963 if(this.lastActive == index){
60964 this.lastActive = false;
60966 var r = this.grid.ds.getAt(index);
60967 this.selections.remove(r);
60968 if(!preventViewNotify){
60969 var view = this.grid.view ? this.grid.view : this.grid;
60970 view.onRowDeselect(index);
60972 this.fireEvent("rowdeselect", this, index);
60973 this.fireEvent("selectionchange", this);
60977 restoreLast : function(){
60979 this.last = this._last;
60984 acceptsNav : function(row, col, cm){
60985 return !cm.isHidden(col) && cm.isCellEditable(col, row);
60989 onEditorKey : function(field, e){
60990 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
60995 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
60997 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
60999 }else if(k == e.ENTER && !e.ctrlKey){
61003 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
61005 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
61007 }else if(k == e.ESC){
61011 g.startEditing(newCell[0], newCell[1]);
61016 * Ext JS Library 1.1.1
61017 * Copyright(c) 2006-2007, Ext JS, LLC.
61019 * Originally Released Under LGPL - original licence link has changed is not relivant.
61022 * <script type="text/javascript">
61025 * @class Roo.grid.CellSelectionModel
61026 * @extends Roo.grid.AbstractSelectionModel
61027 * This class provides the basic implementation for cell selection in a grid.
61029 * @param {Object} config The object containing the configuration of this model.
61030 * @cfg {Boolean} enter_is_tab Enter behaves the same as tab. (eg. goes to next cell) default: false
61032 Roo.grid.CellSelectionModel = function(config){
61033 Roo.apply(this, config);
61035 this.selection = null;
61039 * @event beforerowselect
61040 * Fires before a cell is selected.
61041 * @param {SelectionModel} this
61042 * @param {Number} rowIndex The selected row index
61043 * @param {Number} colIndex The selected cell index
61045 "beforecellselect" : true,
61047 * @event cellselect
61048 * Fires when a cell is selected.
61049 * @param {SelectionModel} this
61050 * @param {Number} rowIndex The selected row index
61051 * @param {Number} colIndex The selected cell index
61053 "cellselect" : true,
61055 * @event selectionchange
61056 * Fires when the active selection changes.
61057 * @param {SelectionModel} this
61058 * @param {Object} selection null for no selection or an object (o) with two properties
61060 <li>o.record: the record object for the row the selection is in</li>
61061 <li>o.cell: An array of [rowIndex, columnIndex]</li>
61064 "selectionchange" : true,
61067 * Fires when the tab (or enter) was pressed on the last editable cell
61068 * You can use this to trigger add new row.
61069 * @param {SelectionModel} this
61073 * @event beforeeditnext
61074 * Fires before the next editable sell is made active
61075 * You can use this to skip to another cell or fire the tabend
61076 * if you set cell to false
61077 * @param {Object} eventdata object : { cell : [ row, col ] }
61079 "beforeeditnext" : true
61081 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
61084 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
61086 enter_is_tab: false,
61089 initEvents : function(){
61090 this.grid.on("mousedown", this.handleMouseDown, this);
61091 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
61092 var view = this.grid.view;
61093 view.on("refresh", this.onViewChange, this);
61094 view.on("rowupdated", this.onRowUpdated, this);
61095 view.on("beforerowremoved", this.clearSelections, this);
61096 view.on("beforerowsinserted", this.clearSelections, this);
61097 if(this.grid.isEditor){
61098 this.grid.on("beforeedit", this.beforeEdit, this);
61103 beforeEdit : function(e){
61104 this.select(e.row, e.column, false, true, e.record);
61108 onRowUpdated : function(v, index, r){
61109 if(this.selection && this.selection.record == r){
61110 v.onCellSelect(index, this.selection.cell[1]);
61115 onViewChange : function(){
61116 this.clearSelections(true);
61120 * Returns the currently selected cell,.
61121 * @return {Array} The selected cell (row, column) or null if none selected.
61123 getSelectedCell : function(){
61124 return this.selection ? this.selection.cell : null;
61128 * Clears all selections.
61129 * @param {Boolean} true to prevent the gridview from being notified about the change.
61131 clearSelections : function(preventNotify){
61132 var s = this.selection;
61134 if(preventNotify !== true){
61135 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
61137 this.selection = null;
61138 this.fireEvent("selectionchange", this, null);
61143 * Returns true if there is a selection.
61144 * @return {Boolean}
61146 hasSelection : function(){
61147 return this.selection ? true : false;
61151 handleMouseDown : function(e, t){
61152 var v = this.grid.getView();
61153 if(this.isLocked()){
61156 var row = v.findRowIndex(t);
61157 var cell = v.findCellIndex(t);
61158 if(row !== false && cell !== false){
61159 this.select(row, cell);
61165 * @param {Number} rowIndex
61166 * @param {Number} collIndex
61168 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
61169 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
61170 this.clearSelections();
61171 r = r || this.grid.dataSource.getAt(rowIndex);
61174 cell : [rowIndex, colIndex]
61176 if(!preventViewNotify){
61177 var v = this.grid.getView();
61178 v.onCellSelect(rowIndex, colIndex);
61179 if(preventFocus !== true){
61180 v.focusCell(rowIndex, colIndex);
61183 this.fireEvent("cellselect", this, rowIndex, colIndex);
61184 this.fireEvent("selectionchange", this, this.selection);
61189 isSelectable : function(rowIndex, colIndex, cm){
61190 return !cm.isHidden(colIndex);
61194 handleKeyDown : function(e){
61195 //Roo.log('Cell Sel Model handleKeyDown');
61196 if(!e.isNavKeyPress()){
61199 var g = this.grid, s = this.selection;
61202 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
61204 this.select(cell[0], cell[1]);
61209 var walk = function(row, col, step){
61210 return g.walkCells(row, col, step, sm.isSelectable, sm);
61212 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
61219 // handled by onEditorKey
61220 if (g.isEditor && g.editing) {
61224 newCell = walk(r, c-1, -1);
61226 newCell = walk(r, c+1, 1);
61231 newCell = walk(r+1, c, 1);
61235 newCell = walk(r-1, c, -1);
61239 newCell = walk(r, c+1, 1);
61243 newCell = walk(r, c-1, -1);
61248 if(g.isEditor && !g.editing){
61249 g.startEditing(r, c);
61258 this.select(newCell[0], newCell[1]);
61264 acceptsNav : function(row, col, cm){
61265 return !cm.isHidden(col) && cm.isCellEditable(col, row);
61269 * @param {Number} field (not used) - as it's normally used as a listener
61270 * @param {Number} e - event - fake it by using
61272 * var e = Roo.EventObjectImpl.prototype;
61273 * e.keyCode = e.TAB
61277 onEditorKey : function(field, e){
61279 var k = e.getKey(),
61282 ed = g.activeEditor,
61284 ///Roo.log('onEditorKey' + k);
61287 if (this.enter_is_tab && k == e.ENTER) {
61293 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
61295 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
61301 } else if(k == e.ENTER && !e.ctrlKey){
61304 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
61306 } else if(k == e.ESC){
61311 var ecall = { cell : newCell, forward : forward };
61312 this.fireEvent('beforeeditnext', ecall );
61313 newCell = ecall.cell;
61314 forward = ecall.forward;
61318 //Roo.log('next cell after edit');
61319 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
61320 } else if (forward) {
61321 // tabbed past last
61322 this.fireEvent.defer(100, this, ['tabend',this]);
61327 * Ext JS Library 1.1.1
61328 * Copyright(c) 2006-2007, Ext JS, LLC.
61330 * Originally Released Under LGPL - original licence link has changed is not relivant.
61333 * <script type="text/javascript">
61337 * @class Roo.grid.EditorGrid
61338 * @extends Roo.grid.Grid
61339 * Class for creating and editable grid.
61340 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
61341 * The container MUST have some type of size defined for the grid to fill. The container will be
61342 * automatically set to position relative if it isn't already.
61343 * @param {Object} dataSource The data model to bind to
61344 * @param {Object} colModel The column model with info about this grid's columns
61346 Roo.grid.EditorGrid = function(container, config){
61347 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
61348 this.getGridEl().addClass("xedit-grid");
61350 if(!this.selModel){
61351 this.selModel = new Roo.grid.CellSelectionModel();
61354 this.activeEditor = null;
61358 * @event beforeedit
61359 * Fires before cell editing is triggered. The edit event object has the following properties <br />
61360 * <ul style="padding:5px;padding-left:16px;">
61361 * <li>grid - This grid</li>
61362 * <li>record - The record being edited</li>
61363 * <li>field - The field name being edited</li>
61364 * <li>value - The value for the field being edited.</li>
61365 * <li>row - The grid row index</li>
61366 * <li>column - The grid column index</li>
61367 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
61369 * @param {Object} e An edit event (see above for description)
61371 "beforeedit" : true,
61374 * Fires after a cell is edited. <br />
61375 * <ul style="padding:5px;padding-left:16px;">
61376 * <li>grid - This grid</li>
61377 * <li>record - The record being edited</li>
61378 * <li>field - The field name being edited</li>
61379 * <li>value - The value being set</li>
61380 * <li>originalValue - The original value for the field, before the edit.</li>
61381 * <li>row - The grid row index</li>
61382 * <li>column - The grid column index</li>
61384 * @param {Object} e An edit event (see above for description)
61386 "afteredit" : true,
61388 * @event validateedit
61389 * Fires after a cell is edited, but before the value is set in the record.
61390 * You can use this to modify the value being set in the field, Return false
61391 * to cancel the change. The edit event object has the following properties <br />
61392 * <ul style="padding:5px;padding-left:16px;">
61393 * <li>editor - This editor</li>
61394 * <li>grid - This grid</li>
61395 * <li>record - The record being edited</li>
61396 * <li>field - The field name being edited</li>
61397 * <li>value - The value being set</li>
61398 * <li>originalValue - The original value for the field, before the edit.</li>
61399 * <li>row - The grid row index</li>
61400 * <li>column - The grid column index</li>
61401 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
61403 * @param {Object} e An edit event (see above for description)
61405 "validateedit" : true
61407 this.on("bodyscroll", this.stopEditing, this);
61408 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
61411 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
61413 * @cfg {Number} clicksToEdit
61414 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
61421 trackMouseOver: false, // causes very odd FF errors
61423 onCellDblClick : function(g, row, col){
61424 this.startEditing(row, col);
61427 onEditComplete : function(ed, value, startValue){
61428 this.editing = false;
61429 this.activeEditor = null;
61430 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
61432 var field = this.colModel.getDataIndex(ed.col);
61437 originalValue: startValue,
61444 var cell = Roo.get(this.view.getCell(ed.row,ed.col));
61447 if(String(value) !== String(startValue)){
61449 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
61450 r.set(field, e.value);
61451 // if we are dealing with a combo box..
61452 // then we also set the 'name' colum to be the displayField
61453 if (ed.field.displayField && ed.field.name) {
61454 r.set(ed.field.name, ed.field.el.dom.value);
61457 delete e.cancel; //?? why!!!
61458 this.fireEvent("afteredit", e);
61461 this.fireEvent("afteredit", e); // always fire it!
61463 this.view.focusCell(ed.row, ed.col);
61467 * Starts editing the specified for the specified row/column
61468 * @param {Number} rowIndex
61469 * @param {Number} colIndex
61471 startEditing : function(row, col){
61472 this.stopEditing();
61473 if(this.colModel.isCellEditable(col, row)){
61474 this.view.ensureVisible(row, col, true);
61476 var r = this.dataSource.getAt(row);
61477 var field = this.colModel.getDataIndex(col);
61478 var cell = Roo.get(this.view.getCell(row,col));
61483 value: r.data[field],
61488 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
61489 this.editing = true;
61490 var ed = this.colModel.getCellEditor(col, row);
61496 ed.render(ed.parentEl || document.body);
61502 (function(){ // complex but required for focus issues in safari, ie and opera
61506 ed.on("complete", this.onEditComplete, this, {single: true});
61507 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
61508 this.activeEditor = ed;
61509 var v = r.data[field];
61510 ed.startEdit(this.view.getCell(row, col), v);
61511 // combo's with 'displayField and name set
61512 if (ed.field.displayField && ed.field.name) {
61513 ed.field.el.dom.value = r.data[ed.field.name];
61517 }).defer(50, this);
61523 * Stops any active editing
61525 stopEditing : function(){
61526 if(this.activeEditor){
61527 this.activeEditor.completeEdit();
61529 this.activeEditor = null;
61533 * Called to get grid's drag proxy text, by default returns this.ddText.
61536 getDragDropText : function(){
61537 var count = this.selModel.getSelectedCell() ? 1 : 0;
61538 return String.format(this.ddText, count, count == 1 ? '' : 's');
61543 * Ext JS Library 1.1.1
61544 * Copyright(c) 2006-2007, Ext JS, LLC.
61546 * Originally Released Under LGPL - original licence link has changed is not relivant.
61549 * <script type="text/javascript">
61552 // private - not really -- you end up using it !
61553 // This is a support class used internally by the Grid components
61556 * @class Roo.grid.GridEditor
61557 * @extends Roo.Editor
61558 * Class for creating and editable grid elements.
61559 * @param {Object} config any settings (must include field)
61561 Roo.grid.GridEditor = function(field, config){
61562 if (!config && field.field) {
61564 field = Roo.factory(config.field, Roo.form);
61566 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
61567 field.monitorTab = false;
61570 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
61573 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
61576 alignment: "tl-tl",
61579 cls: "x-small-editor x-grid-editor",
61584 * Ext JS Library 1.1.1
61585 * Copyright(c) 2006-2007, Ext JS, LLC.
61587 * Originally Released Under LGPL - original licence link has changed is not relivant.
61590 * <script type="text/javascript">
61595 Roo.grid.PropertyRecord = Roo.data.Record.create([
61596 {name:'name',type:'string'}, 'value'
61600 Roo.grid.PropertyStore = function(grid, source){
61602 this.store = new Roo.data.Store({
61603 recordType : Roo.grid.PropertyRecord
61605 this.store.on('update', this.onUpdate, this);
61607 this.setSource(source);
61609 Roo.grid.PropertyStore.superclass.constructor.call(this);
61614 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
61615 setSource : function(o){
61617 this.store.removeAll();
61620 if(this.isEditableValue(o[k])){
61621 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
61624 this.store.loadRecords({records: data}, {}, true);
61627 onUpdate : function(ds, record, type){
61628 if(type == Roo.data.Record.EDIT){
61629 var v = record.data['value'];
61630 var oldValue = record.modified['value'];
61631 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
61632 this.source[record.id] = v;
61634 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
61641 getProperty : function(row){
61642 return this.store.getAt(row);
61645 isEditableValue: function(val){
61646 if(val && val instanceof Date){
61648 }else if(typeof val == 'object' || typeof val == 'function'){
61654 setValue : function(prop, value){
61655 this.source[prop] = value;
61656 this.store.getById(prop).set('value', value);
61659 getSource : function(){
61660 return this.source;
61664 Roo.grid.PropertyColumnModel = function(grid, store){
61667 g.PropertyColumnModel.superclass.constructor.call(this, [
61668 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
61669 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
61671 this.store = store;
61672 this.bselect = Roo.DomHelper.append(document.body, {
61673 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
61674 {tag: 'option', value: 'true', html: 'true'},
61675 {tag: 'option', value: 'false', html: 'false'}
61678 Roo.id(this.bselect);
61681 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
61682 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
61683 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
61684 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
61685 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
61687 this.renderCellDelegate = this.renderCell.createDelegate(this);
61688 this.renderPropDelegate = this.renderProp.createDelegate(this);
61691 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
61695 valueText : 'Value',
61697 dateFormat : 'm/j/Y',
61700 renderDate : function(dateVal){
61701 return dateVal.dateFormat(this.dateFormat);
61704 renderBool : function(bVal){
61705 return bVal ? 'true' : 'false';
61708 isCellEditable : function(colIndex, rowIndex){
61709 return colIndex == 1;
61712 getRenderer : function(col){
61714 this.renderCellDelegate : this.renderPropDelegate;
61717 renderProp : function(v){
61718 return this.getPropertyName(v);
61721 renderCell : function(val){
61723 if(val instanceof Date){
61724 rv = this.renderDate(val);
61725 }else if(typeof val == 'boolean'){
61726 rv = this.renderBool(val);
61728 return Roo.util.Format.htmlEncode(rv);
61731 getPropertyName : function(name){
61732 var pn = this.grid.propertyNames;
61733 return pn && pn[name] ? pn[name] : name;
61736 getCellEditor : function(colIndex, rowIndex){
61737 var p = this.store.getProperty(rowIndex);
61738 var n = p.data['name'], val = p.data['value'];
61740 if(typeof(this.grid.customEditors[n]) == 'string'){
61741 return this.editors[this.grid.customEditors[n]];
61743 if(typeof(this.grid.customEditors[n]) != 'undefined'){
61744 return this.grid.customEditors[n];
61746 if(val instanceof Date){
61747 return this.editors['date'];
61748 }else if(typeof val == 'number'){
61749 return this.editors['number'];
61750 }else if(typeof val == 'boolean'){
61751 return this.editors['boolean'];
61753 return this.editors['string'];
61759 * @class Roo.grid.PropertyGrid
61760 * @extends Roo.grid.EditorGrid
61761 * This class represents the interface of a component based property grid control.
61762 * <br><br>Usage:<pre><code>
61763 var grid = new Roo.grid.PropertyGrid("my-container-id", {
61771 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
61772 * The container MUST have some type of size defined for the grid to fill. The container will be
61773 * automatically set to position relative if it isn't already.
61774 * @param {Object} config A config object that sets properties on this grid.
61776 Roo.grid.PropertyGrid = function(container, config){
61777 config = config || {};
61778 var store = new Roo.grid.PropertyStore(this);
61779 this.store = store;
61780 var cm = new Roo.grid.PropertyColumnModel(this, store);
61781 store.store.sort('name', 'ASC');
61782 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
61785 enableColLock:false,
61786 enableColumnMove:false,
61788 trackMouseOver: false,
61791 this.getGridEl().addClass('x-props-grid');
61792 this.lastEditRow = null;
61793 this.on('columnresize', this.onColumnResize, this);
61796 * @event beforepropertychange
61797 * Fires before a property changes (return false to stop?)
61798 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
61799 * @param {String} id Record Id
61800 * @param {String} newval New Value
61801 * @param {String} oldval Old Value
61803 "beforepropertychange": true,
61805 * @event propertychange
61806 * Fires after a property changes
61807 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
61808 * @param {String} id Record Id
61809 * @param {String} newval New Value
61810 * @param {String} oldval Old Value
61812 "propertychange": true
61814 this.customEditors = this.customEditors || {};
61816 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
61819 * @cfg {Object} customEditors map of colnames=> custom editors.
61820 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
61821 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
61822 * false disables editing of the field.
61826 * @cfg {Object} propertyNames map of property Names to their displayed value
61829 render : function(){
61830 Roo.grid.PropertyGrid.superclass.render.call(this);
61831 this.autoSize.defer(100, this);
61834 autoSize : function(){
61835 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
61837 this.view.fitColumns();
61841 onColumnResize : function(){
61842 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
61846 * Sets the data for the Grid
61847 * accepts a Key => Value object of all the elements avaiable.
61848 * @param {Object} data to appear in grid.
61850 setSource : function(source){
61851 this.store.setSource(source);
61855 * Gets all the data from the grid.
61856 * @return {Object} data data stored in grid
61858 getSource : function(){
61859 return this.store.getSource();
61868 * @class Roo.grid.Calendar
61869 * @extends Roo.grid.Grid
61870 * This class extends the Grid to provide a calendar widget
61871 * <br><br>Usage:<pre><code>
61872 var grid = new Roo.grid.Calendar("my-container-id", {
61875 selModel: mySelectionModel,
61876 autoSizeColumns: true,
61877 monitorWindowResize: false,
61878 trackMouseOver: true
61879 eventstore : real data store..
61885 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
61886 * The container MUST have some type of size defined for the grid to fill. The container will be
61887 * automatically set to position relative if it isn't already.
61888 * @param {Object} config A config object that sets properties on this grid.
61890 Roo.grid.Calendar = function(container, config){
61891 // initialize the container
61892 this.container = Roo.get(container);
61893 this.container.update("");
61894 this.container.setStyle("overflow", "hidden");
61895 this.container.addClass('x-grid-container');
61897 this.id = this.container.id;
61899 Roo.apply(this, config);
61900 // check and correct shorthanded configs
61904 for (var r = 0;r < 6;r++) {
61907 for (var c =0;c < 7;c++) {
61911 if (this.eventStore) {
61912 this.eventStore= Roo.factory(this.eventStore, Roo.data);
61913 this.eventStore.on('load',this.onLoad, this);
61914 this.eventStore.on('beforeload',this.clearEvents, this);
61918 this.dataSource = new Roo.data.Store({
61919 proxy: new Roo.data.MemoryProxy(rows),
61920 reader: new Roo.data.ArrayReader({}, [
61921 'weekday0', 'weekday1', 'weekday2', 'weekday3', 'weekday4', 'weekday5', 'weekday6' ])
61924 this.dataSource.load();
61925 this.ds = this.dataSource;
61926 this.ds.xmodule = this.xmodule || false;
61929 var cellRender = function(v,x,r)
61931 return String.format(
61932 '<div class="fc-day fc-widget-content"><div>' +
61933 '<div class="fc-event-container"></div>' +
61934 '<div class="fc-day-number">{0}</div>'+
61936 '<div class="fc-day-content"><div style="position:relative"></div></div>' +
61937 '</div></div>', v);
61942 this.colModel = new Roo.grid.ColumnModel( [
61944 xtype: 'ColumnModel',
61946 dataIndex : 'weekday0',
61948 renderer : cellRender
61951 xtype: 'ColumnModel',
61953 dataIndex : 'weekday1',
61955 renderer : cellRender
61958 xtype: 'ColumnModel',
61960 dataIndex : 'weekday2',
61961 header : 'Tuesday',
61962 renderer : cellRender
61965 xtype: 'ColumnModel',
61967 dataIndex : 'weekday3',
61968 header : 'Wednesday',
61969 renderer : cellRender
61972 xtype: 'ColumnModel',
61974 dataIndex : 'weekday4',
61975 header : 'Thursday',
61976 renderer : cellRender
61979 xtype: 'ColumnModel',
61981 dataIndex : 'weekday5',
61983 renderer : cellRender
61986 xtype: 'ColumnModel',
61988 dataIndex : 'weekday6',
61989 header : 'Saturday',
61990 renderer : cellRender
61993 this.cm = this.colModel;
61994 this.cm.xmodule = this.xmodule || false;
61998 //this.selModel = new Roo.grid.CellSelectionModel();
61999 //this.sm = this.selModel;
62000 //this.selModel.init(this);
62004 this.container.setWidth(this.width);
62008 this.container.setHeight(this.height);
62015 * The raw click event for the entire grid.
62016 * @param {Roo.EventObject} e
62021 * The raw dblclick event for the entire grid.
62022 * @param {Roo.EventObject} e
62026 * @event contextmenu
62027 * The raw contextmenu event for the entire grid.
62028 * @param {Roo.EventObject} e
62030 "contextmenu" : true,
62033 * The raw mousedown event for the entire grid.
62034 * @param {Roo.EventObject} e
62036 "mousedown" : true,
62039 * The raw mouseup event for the entire grid.
62040 * @param {Roo.EventObject} e
62045 * The raw mouseover event for the entire grid.
62046 * @param {Roo.EventObject} e
62048 "mouseover" : true,
62051 * The raw mouseout event for the entire grid.
62052 * @param {Roo.EventObject} e
62057 * The raw keypress event for the entire grid.
62058 * @param {Roo.EventObject} e
62063 * The raw keydown event for the entire grid.
62064 * @param {Roo.EventObject} e
62072 * Fires when a cell is clicked
62073 * @param {Grid} this
62074 * @param {Number} rowIndex
62075 * @param {Number} columnIndex
62076 * @param {Roo.EventObject} e
62078 "cellclick" : true,
62080 * @event celldblclick
62081 * Fires when a cell is double clicked
62082 * @param {Grid} this
62083 * @param {Number} rowIndex
62084 * @param {Number} columnIndex
62085 * @param {Roo.EventObject} e
62087 "celldblclick" : true,
62090 * Fires when a row is clicked
62091 * @param {Grid} this
62092 * @param {Number} rowIndex
62093 * @param {Roo.EventObject} e
62097 * @event rowdblclick
62098 * Fires when a row is double clicked
62099 * @param {Grid} this
62100 * @param {Number} rowIndex
62101 * @param {Roo.EventObject} e
62103 "rowdblclick" : true,
62105 * @event headerclick
62106 * Fires when a header is clicked
62107 * @param {Grid} this
62108 * @param {Number} columnIndex
62109 * @param {Roo.EventObject} e
62111 "headerclick" : true,
62113 * @event headerdblclick
62114 * Fires when a header cell is double clicked
62115 * @param {Grid} this
62116 * @param {Number} columnIndex
62117 * @param {Roo.EventObject} e
62119 "headerdblclick" : true,
62121 * @event rowcontextmenu
62122 * Fires when a row is right clicked
62123 * @param {Grid} this
62124 * @param {Number} rowIndex
62125 * @param {Roo.EventObject} e
62127 "rowcontextmenu" : true,
62129 * @event cellcontextmenu
62130 * Fires when a cell is right clicked
62131 * @param {Grid} this
62132 * @param {Number} rowIndex
62133 * @param {Number} cellIndex
62134 * @param {Roo.EventObject} e
62136 "cellcontextmenu" : true,
62138 * @event headercontextmenu
62139 * Fires when a header is right clicked
62140 * @param {Grid} this
62141 * @param {Number} columnIndex
62142 * @param {Roo.EventObject} e
62144 "headercontextmenu" : true,
62146 * @event bodyscroll
62147 * Fires when the body element is scrolled
62148 * @param {Number} scrollLeft
62149 * @param {Number} scrollTop
62151 "bodyscroll" : true,
62153 * @event columnresize
62154 * Fires when the user resizes a column
62155 * @param {Number} columnIndex
62156 * @param {Number} newSize
62158 "columnresize" : true,
62160 * @event columnmove
62161 * Fires when the user moves a column
62162 * @param {Number} oldIndex
62163 * @param {Number} newIndex
62165 "columnmove" : true,
62168 * Fires when row(s) start being dragged
62169 * @param {Grid} this
62170 * @param {Roo.GridDD} dd The drag drop object
62171 * @param {event} e The raw browser event
62173 "startdrag" : true,
62176 * Fires when a drag operation is complete
62177 * @param {Grid} this
62178 * @param {Roo.GridDD} dd The drag drop object
62179 * @param {event} e The raw browser event
62184 * Fires when dragged row(s) are dropped on a valid DD target
62185 * @param {Grid} this
62186 * @param {Roo.GridDD} dd The drag drop object
62187 * @param {String} targetId The target drag drop object
62188 * @param {event} e The raw browser event
62193 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
62194 * @param {Grid} this
62195 * @param {Roo.GridDD} dd The drag drop object
62196 * @param {String} targetId The target drag drop object
62197 * @param {event} e The raw browser event
62202 * Fires when the dragged row(s) first cross another DD target while being dragged
62203 * @param {Grid} this
62204 * @param {Roo.GridDD} dd The drag drop object
62205 * @param {String} targetId The target drag drop object
62206 * @param {event} e The raw browser event
62208 "dragenter" : true,
62211 * Fires when the dragged row(s) leave another DD target while being dragged
62212 * @param {Grid} this
62213 * @param {Roo.GridDD} dd The drag drop object
62214 * @param {String} targetId The target drag drop object
62215 * @param {event} e The raw browser event
62220 * Fires when a row is rendered, so you can change add a style to it.
62221 * @param {GridView} gridview The grid view
62222 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
62228 * Fires when the grid is rendered
62229 * @param {Grid} grid
62234 * Fires when a date is selected
62235 * @param {DatePicker} this
62236 * @param {Date} date The selected date
62240 * @event monthchange
62241 * Fires when the displayed month changes
62242 * @param {DatePicker} this
62243 * @param {Date} date The selected month
62245 'monthchange': true,
62247 * @event evententer
62248 * Fires when mouse over an event
62249 * @param {Calendar} this
62250 * @param {event} Event
62252 'evententer': true,
62254 * @event eventleave
62255 * Fires when the mouse leaves an
62256 * @param {Calendar} this
62259 'eventleave': true,
62261 * @event eventclick
62262 * Fires when the mouse click an
62263 * @param {Calendar} this
62266 'eventclick': true,
62268 * @event eventrender
62269 * Fires before each cell is rendered, so you can modify the contents, like cls / title / qtip
62270 * @param {Calendar} this
62271 * @param {data} data to be modified
62273 'eventrender': true
62277 Roo.grid.Grid.superclass.constructor.call(this);
62278 this.on('render', function() {
62279 this.view.el.addClass('x-grid-cal');
62281 (function() { this.setDate(new Date()); }).defer(100,this); //default today..
62285 if (!Roo.grid.Calendar.style) {
62286 Roo.grid.Calendar.style = Roo.util.CSS.createStyleSheet({
62289 '.x-grid-cal .x-grid-col' : {
62290 height: 'auto !important',
62291 'vertical-align': 'top'
62293 '.x-grid-cal .fc-event-hori' : {
62304 Roo.extend(Roo.grid.Calendar, Roo.grid.Grid, {
62306 * @cfg {Store} eventStore The store that loads events.
62311 activeDate : false,
62314 monitorWindowResize : false,
62317 resizeColumns : function() {
62318 var col = (this.view.el.getWidth() / 7) - 3;
62319 // loop through cols, and setWidth
62320 for(var i =0 ; i < 7 ; i++){
62321 this.cm.setColumnWidth(i, col);
62324 setDate :function(date) {
62326 Roo.log('setDate?');
62328 this.resizeColumns();
62329 var vd = this.activeDate;
62330 this.activeDate = date;
62331 // if(vd && this.el){
62332 // var t = date.getTime();
62333 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
62334 // Roo.log('using add remove');
62336 // this.fireEvent('monthchange', this, date);
62338 // this.cells.removeClass("fc-state-highlight");
62339 // this.cells.each(function(c){
62340 // if(c.dateValue == t){
62341 // c.addClass("fc-state-highlight");
62342 // setTimeout(function(){
62343 // try{c.dom.firstChild.focus();}catch(e){}
62353 var days = date.getDaysInMonth();
62355 var firstOfMonth = date.getFirstDateOfMonth();
62356 var startingPos = firstOfMonth.getDay()-this.startDay;
62358 if(startingPos < this.startDay){
62362 var pm = date.add(Date.MONTH, -1);
62363 var prevStart = pm.getDaysInMonth()-startingPos;
62367 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
62369 this.textNodes = this.view.el.query('.x-grid-row .x-grid-col .x-grid-cell-text');
62370 //this.cells.addClassOnOver('fc-state-hover');
62372 var cells = this.cells.elements;
62373 var textEls = this.textNodes;
62375 //Roo.each(cells, function(cell){
62376 // cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
62379 days += startingPos;
62381 // convert everything to numbers so it's fast
62382 var day = 86400000;
62383 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
62386 //Roo.log(prevStart);
62388 var today = new Date().clearTime().getTime();
62389 var sel = date.clearTime().getTime();
62390 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
62391 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
62392 var ddMatch = this.disabledDatesRE;
62393 var ddText = this.disabledDatesText;
62394 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
62395 var ddaysText = this.disabledDaysText;
62396 var format = this.format;
62398 var setCellClass = function(cal, cell){
62400 //Roo.log('set Cell Class');
62402 var t = d.getTime();
62407 cell.dateValue = t;
62409 cell.className += " fc-today";
62410 cell.className += " fc-state-highlight";
62411 cell.title = cal.todayText;
62414 // disable highlight in other month..
62415 cell.className += " fc-state-highlight";
62420 //cell.className = " fc-state-disabled";
62421 cell.title = cal.minText;
62425 //cell.className = " fc-state-disabled";
62426 cell.title = cal.maxText;
62430 if(ddays.indexOf(d.getDay()) != -1){
62431 // cell.title = ddaysText;
62432 // cell.className = " fc-state-disabled";
62435 if(ddMatch && format){
62436 var fvalue = d.dateFormat(format);
62437 if(ddMatch.test(fvalue)){
62438 cell.title = ddText.replace("%0", fvalue);
62439 cell.className = " fc-state-disabled";
62443 if (!cell.initialClassName) {
62444 cell.initialClassName = cell.dom.className;
62447 cell.dom.className = cell.initialClassName + ' ' + cell.className;
62452 for(; i < startingPos; i++) {
62453 cells[i].dayName = (++prevStart);
62454 Roo.log(textEls[i]);
62455 d.setDate(d.getDate()+1);
62457 //cells[i].className = "fc-past fc-other-month";
62458 setCellClass(this, cells[i]);
62463 for(; i < days; i++){
62464 intDay = i - startingPos + 1;
62465 cells[i].dayName = (intDay);
62466 d.setDate(d.getDate()+1);
62468 cells[i].className = ''; // "x-date-active";
62469 setCellClass(this, cells[i]);
62473 for(; i < 42; i++) {
62474 //textEls[i].innerHTML = (++extraDays);
62476 d.setDate(d.getDate()+1);
62477 cells[i].dayName = (++extraDays);
62478 cells[i].className = "fc-future fc-other-month";
62479 setCellClass(this, cells[i]);
62482 //this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
62484 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
62486 // this will cause all the cells to mis
62489 for (var r = 0;r < 6;r++) {
62490 for (var c =0;c < 7;c++) {
62491 this.ds.getAt(r).set('weekday' + c ,cells[i++].dayName );
62495 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
62496 for(i=0;i<cells.length;i++) {
62498 this.cells.elements[i].dayName = cells[i].dayName ;
62499 this.cells.elements[i].className = cells[i].className;
62500 this.cells.elements[i].initialClassName = cells[i].initialClassName ;
62501 this.cells.elements[i].title = cells[i].title ;
62502 this.cells.elements[i].dateValue = cells[i].dateValue ;
62508 //this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
62509 //this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
62511 ////if(totalRows != 6){
62512 //this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
62513 // this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
62516 this.fireEvent('monthchange', this, date);
62521 * Returns the grid's SelectionModel.
62522 * @return {SelectionModel}
62524 getSelectionModel : function(){
62525 if(!this.selModel){
62526 this.selModel = new Roo.grid.CellSelectionModel();
62528 return this.selModel;
62532 this.eventStore.load()
62538 findCell : function(dt) {
62539 dt = dt.clearTime().getTime();
62541 this.cells.each(function(c){
62542 //Roo.log("check " +c.dateValue + '?=' + dt);
62543 if(c.dateValue == dt){
62553 findCells : function(rec) {
62554 var s = rec.data.start_dt.clone().clearTime().getTime();
62556 var e= rec.data.end_dt.clone().clearTime().getTime();
62559 this.cells.each(function(c){
62560 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
62562 if(c.dateValue > e){
62565 if(c.dateValue < s){
62574 findBestRow: function(cells)
62578 for (var i =0 ; i < cells.length;i++) {
62579 ret = Math.max(cells[i].rows || 0,ret);
62586 addItem : function(rec)
62588 // look for vertical location slot in
62589 var cells = this.findCells(rec);
62591 rec.row = this.findBestRow(cells);
62593 // work out the location.
62597 for(var i =0; i < cells.length; i++) {
62605 if (crow.start.getY() == cells[i].getY()) {
62607 crow.end = cells[i];
62623 for (var i = 0; i < cells.length;i++) {
62624 cells[i].rows = Math.max(cells[i].rows || 0 , rec.row + 1 );
62631 clearEvents: function() {
62633 if (!this.eventStore.getCount()) {
62636 // reset number of rows in cells.
62637 Roo.each(this.cells.elements, function(c){
62641 this.eventStore.each(function(e) {
62642 this.clearEvent(e);
62647 clearEvent : function(ev)
62650 Roo.each(ev.els, function(el) {
62651 el.un('mouseenter' ,this.onEventEnter, this);
62652 el.un('mouseleave' ,this.onEventLeave, this);
62660 renderEvent : function(ev,ctr) {
62662 ctr = this.view.el.select('.fc-event-container',true).first();
62666 this.clearEvent(ev);
62672 var cells = ev.cells;
62673 var rows = ev.rows;
62674 this.fireEvent('eventrender', this, ev);
62676 for(var i =0; i < rows.length; i++) {
62680 cls += ' fc-event-start';
62682 if ((i+1) == rows.length) {
62683 cls += ' fc-event-end';
62686 //Roo.log(ev.data);
62687 // how many rows should it span..
62688 var cg = this.eventTmpl.append(ctr,Roo.apply({
62691 }, ev.data) , true);
62694 cg.on('mouseenter' ,this.onEventEnter, this, ev);
62695 cg.on('mouseleave' ,this.onEventLeave, this, ev);
62696 cg.on('click', this.onEventClick, this, ev);
62700 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
62701 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
62704 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);
62705 cg.setWidth(ebox.right - sbox.x -2);
62709 renderEvents: function()
62711 // first make sure there is enough space..
62713 if (!this.eventTmpl) {
62714 this.eventTmpl = new Roo.Template(
62715 '<div class="roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable {fccls} {cls}" style="position: absolute" unselectable="on">' +
62716 '<div class="fc-event-inner">' +
62717 '<span class="fc-event-time">{time}</span>' +
62718 '<span class="fc-event-title" qtip="{qtip}">{title}</span>' +
62720 '<div class="ui-resizable-heandle ui-resizable-e"> </div>' +
62728 this.cells.each(function(c) {
62729 //Roo.log(c.select('.fc-day-content div',true).first());
62730 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, (c.rows || 1) * 20));
62733 var ctr = this.view.el.select('.fc-event-container',true).first();
62736 this.eventStore.each(function(ev){
62738 this.renderEvent(ev);
62742 this.view.layout();
62746 onEventEnter: function (e, el,event,d) {
62747 this.fireEvent('evententer', this, el, event);
62750 onEventLeave: function (e, el,event,d) {
62751 this.fireEvent('eventleave', this, el, event);
62754 onEventClick: function (e, el,event,d) {
62755 this.fireEvent('eventclick', this, el, event);
62758 onMonthChange: function () {
62762 onLoad: function () {
62764 //Roo.log('calendar onload');
62766 if(this.eventStore.getCount() > 0){
62770 this.eventStore.each(function(d){
62775 if (typeof(add.end_dt) == 'undefined') {
62776 Roo.log("Missing End time in calendar data: ");
62780 if (typeof(add.start_dt) == 'undefined') {
62781 Roo.log("Missing Start time in calendar data: ");
62785 add.start_dt = typeof(add.start_dt) == 'string' ? Date.parseDate(add.start_dt,'Y-m-d H:i:s') : add.start_dt,
62786 add.end_dt = typeof(add.end_dt) == 'string' ? Date.parseDate(add.end_dt,'Y-m-d H:i:s') : add.end_dt,
62787 add.id = add.id || d.id;
62788 add.title = add.title || '??';
62796 this.renderEvents();
62806 render : function ()
62810 if (!this.view.el.hasClass('course-timesheet')) {
62811 this.view.el.addClass('course-timesheet');
62813 if (this.tsStyle) {
62818 Roo.log(_this.grid.view.el.getWidth());
62821 this.tsStyle = Roo.util.CSS.createStyleSheet({
62822 '.course-timesheet .x-grid-row' : {
62825 '.x-grid-row td' : {
62826 'vertical-align' : 0
62828 '.course-edit-link' : {
62830 'text-overflow' : 'ellipsis',
62831 'overflow' : 'hidden',
62832 'white-space' : 'nowrap',
62833 'cursor' : 'pointer'
62838 '.de-act-sup-link' : {
62839 'color' : 'purple',
62840 'text-decoration' : 'line-through'
62844 'text-decoration' : 'line-through'
62846 '.course-timesheet .course-highlight' : {
62847 'border-top-style': 'dashed !important',
62848 'border-bottom-bottom': 'dashed !important'
62850 '.course-timesheet .course-item' : {
62851 'font-family' : 'tahoma, arial, helvetica',
62852 'font-size' : '11px',
62853 'overflow' : 'hidden',
62854 'padding-left' : '10px',
62855 'padding-right' : '10px',
62856 'padding-top' : '10px'
62864 monitorWindowResize : false,
62865 cellrenderer : function(v,x,r)
62870 xtype: 'CellSelectionModel',
62877 beforeload : function (_self, options)
62879 options.params = options.params || {};
62880 options.params._month = _this.monthField.getValue();
62881 options.params.limit = 9999;
62882 options.params['sort'] = 'when_dt';
62883 options.params['dir'] = 'ASC';
62884 this.proxy.loadResponse = this.loadResponse;
62886 //this.addColumns();
62888 load : function (_self, records, options)
62890 _this.grid.view.el.select('.course-edit-link', true).on('click', function() {
62891 // if you click on the translation.. you can edit it...
62892 var el = Roo.get(this);
62893 var id = el.dom.getAttribute('data-id');
62894 var d = el.dom.getAttribute('data-date');
62895 var t = el.dom.getAttribute('data-time');
62896 //var id = this.child('span').dom.textContent;
62899 Pman.Dialog.CourseCalendar.show({
62903 productitem_active : id ? 1 : 0
62905 _this.grid.ds.load({});
62910 _this.panel.fireEvent('resize', [ '', '' ]);
62913 loadResponse : function(o, success, response){
62914 // this is overridden on before load..
62916 Roo.log("our code?");
62917 //Roo.log(success);
62918 //Roo.log(response)
62919 delete this.activeRequest;
62921 this.fireEvent("loadexception", this, o, response);
62922 o.request.callback.call(o.request.scope, null, o.request.arg, false);
62927 result = o.reader.read(response);
62929 Roo.log("load exception?");
62930 this.fireEvent("loadexception", this, o, response, e);
62931 o.request.callback.call(o.request.scope, null, o.request.arg, false);
62934 Roo.log("ready...");
62935 // loop through result.records;
62936 // and set this.tdate[date] = [] << array of records..
62938 Roo.each(result.records, function(r){
62940 if(typeof(_this.tdata[r.data.when_dt.format('j')]) == 'undefined'){
62941 _this.tdata[r.data.when_dt.format('j')] = [];
62943 _this.tdata[r.data.when_dt.format('j')].push(r.data);
62946 //Roo.log(_this.tdata);
62948 result.records = [];
62949 result.totalRecords = 6;
62951 // let's generate some duumy records for the rows.
62952 //var st = _this.dateField.getValue();
62954 // work out monday..
62955 //st = st.add(Date.DAY, -1 * st.format('w'));
62957 var date = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
62959 var firstOfMonth = date.getFirstDayOfMonth();
62960 var days = date.getDaysInMonth();
62962 var firstAdded = false;
62963 for (var i = 0; i < result.totalRecords ; i++) {
62964 //var d= st.add(Date.DAY, i);
62967 for(var w = 0 ; w < 7 ; w++){
62968 if(!firstAdded && firstOfMonth != w){
62975 var dd = (d > 0 && d < 10) ? "0"+d : d;
62976 row['weekday'+w] = String.format(
62977 '<span style="font-size: 16px;"><b>{0}</b></span>'+
62978 '<span class="course-edit-link" style="color:blue;" data-id="0" data-date="{1}"> Add New</span>',
62980 date.format('Y-m-')+dd
62983 if(typeof(_this.tdata[d]) != 'undefined'){
62984 Roo.each(_this.tdata[d], function(r){
62988 var desc = (r.productitem_id_descrip) ? r.productitem_id_descrip : '';
62989 if(r.parent_id*1>0){
62990 is_sub = (r.productitem_id_visible*1 < 1) ? 'de-act-sup-link' :'sub-link';
62993 if(r.productitem_id_visible*1 < 1 && r.parent_id*1 < 1){
62994 deactive = 'de-act-link';
62997 row['weekday'+w] += String.format(
62998 '<br /><span class="course-edit-link {3} {4}" qtip="{5}" data-id="{0}">{2} - {1}</span>',
63000 r.product_id_name, //1
63001 r.when_dt.format('h:ia'), //2
63011 // only do this if something added..
63013 result.records.push(_this.grid.dataSource.reader.newRow(row));
63017 // push it twice. (second one with an hour..
63021 this.fireEvent("load", this, o, o.request.arg);
63022 o.request.callback.call(o.request.scope, result, o.request.arg, true);
63024 sortInfo : {field: 'when_dt', direction : 'ASC' },
63026 xtype: 'HttpProxy',
63029 url : baseURL + '/Roo/Shop_course.php'
63032 xtype: 'JsonReader',
63049 'name': 'parent_id',
63053 'name': 'product_id',
63057 'name': 'productitem_id',
63075 click : function (_self, e)
63077 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
63078 sd.setMonth(sd.getMonth()-1);
63079 _this.monthField.setValue(sd.format('Y-m-d'));
63080 _this.grid.ds.load({});
63086 xtype: 'Separator',
63090 xtype: 'MonthField',
63093 render : function (_self)
63095 _this.monthField = _self;
63096 // _this.monthField.set today
63098 select : function (combo, date)
63100 _this.grid.ds.load({});
63103 value : (function() { return new Date(); })()
63106 xtype: 'Separator',
63112 text : "Blue: in-active, green: in-active sup-event, red: de-active, purple: de-active sup-event"
63122 click : function (_self, e)
63124 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
63125 sd.setMonth(sd.getMonth()+1);
63126 _this.monthField.setValue(sd.format('Y-m-d'));
63127 _this.grid.ds.load({});
63140 * Ext JS Library 1.1.1
63141 * Copyright(c) 2006-2007, Ext JS, LLC.
63143 * Originally Released Under LGPL - original licence link has changed is not relivant.
63146 * <script type="text/javascript">
63150 * @class Roo.LoadMask
63151 * A simple utility class for generically masking elements while loading data. If the element being masked has
63152 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
63153 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
63154 * element's UpdateManager load indicator and will be destroyed after the initial load.
63156 * Create a new LoadMask
63157 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
63158 * @param {Object} config The config object
63160 Roo.LoadMask = function(el, config){
63161 this.el = Roo.get(el);
63162 Roo.apply(this, config);
63164 this.store.on('beforeload', this.onBeforeLoad, this);
63165 this.store.on('load', this.onLoad, this);
63166 this.store.on('loadexception', this.onLoadException, this);
63167 this.removeMask = false;
63169 var um = this.el.getUpdateManager();
63170 um.showLoadIndicator = false; // disable the default indicator
63171 um.on('beforeupdate', this.onBeforeLoad, this);
63172 um.on('update', this.onLoad, this);
63173 um.on('failure', this.onLoad, this);
63174 this.removeMask = true;
63178 Roo.LoadMask.prototype = {
63180 * @cfg {Boolean} removeMask
63181 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
63182 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
63184 removeMask : false,
63186 * @cfg {String} msg
63187 * The text to display in a centered loading message box (defaults to 'Loading...')
63189 msg : 'Loading...',
63191 * @cfg {String} msgCls
63192 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
63194 msgCls : 'x-mask-loading',
63197 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
63203 * Disables the mask to prevent it from being displayed
63205 disable : function(){
63206 this.disabled = true;
63210 * Enables the mask so that it can be displayed
63212 enable : function(){
63213 this.disabled = false;
63216 onLoadException : function()
63218 Roo.log(arguments);
63220 if (typeof(arguments[3]) != 'undefined') {
63221 Roo.MessageBox.alert("Error loading",arguments[3]);
63225 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
63226 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
63233 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
63236 onLoad : function()
63238 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
63242 onBeforeLoad : function(){
63243 if(!this.disabled){
63244 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
63249 destroy : function(){
63251 this.store.un('beforeload', this.onBeforeLoad, this);
63252 this.store.un('load', this.onLoad, this);
63253 this.store.un('loadexception', this.onLoadException, this);
63255 var um = this.el.getUpdateManager();
63256 um.un('beforeupdate', this.onBeforeLoad, this);
63257 um.un('update', this.onLoad, this);
63258 um.un('failure', this.onLoad, this);
63263 * Ext JS Library 1.1.1
63264 * Copyright(c) 2006-2007, Ext JS, LLC.
63266 * Originally Released Under LGPL - original licence link has changed is not relivant.
63269 * <script type="text/javascript">
63274 * @class Roo.XTemplate
63275 * @extends Roo.Template
63276 * Provides a template that can have nested templates for loops or conditionals. The syntax is:
63278 var t = new Roo.XTemplate(
63279 '<select name="{name}">',
63280 '<tpl for="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
63284 // then append, applying the master template values
63287 * Supported features:
63292 {a_variable} - output encoded.
63293 {a_variable.format:("Y-m-d")} - call a method on the variable
63294 {a_variable:raw} - unencoded output
63295 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
63296 {a_variable:this.method_on_template(...)} - call a method on the template object.
63301 <tpl for="a_variable or condition.."></tpl>
63302 <tpl if="a_variable or condition"></tpl>
63303 <tpl exec="some javascript"></tpl>
63304 <tpl name="named_template"></tpl> (experimental)
63306 <tpl for="."></tpl> - just iterate the property..
63307 <tpl for=".."></tpl> - iterates with the parent (probably the template)
63311 Roo.XTemplate = function()
63313 Roo.XTemplate.superclass.constructor.apply(this, arguments);
63320 Roo.extend(Roo.XTemplate, Roo.Template, {
63323 * The various sub templates
63328 * basic tag replacing syntax
63331 * // you can fake an object call by doing this
63335 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
63338 * compile the template
63340 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
63343 compile: function()
63347 s = ['<tpl>', s, '</tpl>'].join('');
63349 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
63350 nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
63351 ifRe = /^<tpl\b[^>]*?if="(.*?)"/,
63352 execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
63353 namedRe = /^<tpl\b[^>]*?name="(\w+)"/, // named templates..
63358 while(true == !!(m = s.match(re))){
63359 var forMatch = m[0].match(nameRe),
63360 ifMatch = m[0].match(ifRe),
63361 execMatch = m[0].match(execRe),
63362 namedMatch = m[0].match(namedRe),
63367 name = forMatch && forMatch[1] ? forMatch[1] : '';
63370 // if - puts fn into test..
63371 exp = ifMatch && ifMatch[1] ? ifMatch[1] : null;
63373 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
63378 // exec - calls a function... returns empty if true is returned.
63379 exp = execMatch && execMatch[1] ? execMatch[1] : null;
63381 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
63389 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
63390 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
63391 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
63394 var uid = namedMatch ? namedMatch[1] : id;
63398 id: namedMatch ? namedMatch[1] : id,
63405 s = s.replace(m[0], '');
63407 s = s.replace(m[0], '{xtpl'+ id + '}');
63412 for(var i = tpls.length-1; i >= 0; --i){
63413 this.compileTpl(tpls[i]);
63414 this.tpls[tpls[i].id] = tpls[i];
63416 this.master = tpls[tpls.length-1];
63420 * same as applyTemplate, except it's done to one of the subTemplates
63421 * when using named templates, you can do:
63423 * var str = pl.applySubTemplate('your-name', values);
63426 * @param {Number} id of the template
63427 * @param {Object} values to apply to template
63428 * @param {Object} parent (normaly the instance of this object)
63430 applySubTemplate : function(id, values, parent)
63434 var t = this.tpls[id];
63438 if(t.test && !t.test.call(this, values, parent)){
63442 Roo.log("Xtemplate.applySubTemplate 'test': Exception thrown");
63443 Roo.log(e.toString());
63449 if(t.exec && t.exec.call(this, values, parent)){
63453 Roo.log("Xtemplate.applySubTemplate 'exec': Exception thrown");
63454 Roo.log(e.toString());
63459 var vs = t.target ? t.target.call(this, values, parent) : values;
63460 parent = t.target ? values : parent;
63461 if(t.target && vs instanceof Array){
63463 for(var i = 0, len = vs.length; i < len; i++){
63464 buf[buf.length] = t.compiled.call(this, vs[i], parent);
63466 return buf.join('');
63468 return t.compiled.call(this, vs, parent);
63470 Roo.log("Xtemplate.applySubTemplate : Exception thrown");
63471 Roo.log(e.toString());
63472 Roo.log(t.compiled);
63477 compileTpl : function(tpl)
63479 var fm = Roo.util.Format;
63480 var useF = this.disableFormats !== true;
63481 var sep = Roo.isGecko ? "+" : ",";
63482 var undef = function(str) {
63483 Roo.log("Property not found :" + str);
63487 var fn = function(m, name, format, args)
63489 //Roo.log(arguments);
63490 args = args ? args.replace(/\\'/g,"'") : args;
63491 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
63492 if (typeof(format) == 'undefined') {
63493 format= 'htmlEncode';
63495 if (format == 'raw' ) {
63499 if(name.substr(0, 4) == 'xtpl'){
63500 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
63503 // build an array of options to determine if value is undefined..
63505 // basically get 'xxxx.yyyy' then do
63506 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
63507 // (function () { Roo.log("Property not found"); return ''; })() :
63512 Roo.each(name.split('.'), function(st) {
63513 lookfor += (lookfor.length ? '.': '') + st;
63514 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
63517 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
63520 if(format && useF){
63522 args = args ? ',' + args : "";
63524 if(format.substr(0, 5) != "this."){
63525 format = "fm." + format + '(';
63527 format = 'this.call("'+ format.substr(5) + '", ';
63531 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
63535 // called with xxyx.yuu:(test,test)
63537 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
63539 // raw.. - :raw modifier..
63540 return "'"+ sep + udef_st + name + ")"+sep+"'";
63544 // branched to use + in gecko and [].join() in others
63546 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
63547 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
63550 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
63551 body.push(tpl.body.replace(/(\r\n|\n)/g,
63552 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
63553 body.push("'].join('');};};");
63554 body = body.join('');
63557 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
63559 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
63565 applyTemplate : function(values){
63566 return this.master.compiled.call(this, values, {});
63567 //var s = this.subs;
63570 apply : function(){
63571 return this.applyTemplate.apply(this, arguments);
63576 Roo.XTemplate.from = function(el){
63577 el = Roo.getDom(el);
63578 return new Roo.XTemplate(el.value || el.innerHTML);