4 * Copyright(c) 2006-2007, Ext JS, LLC.
6 * Originally Released Under LGPL - original licence link has changed is not relivant.
9 * <script type="text/javascript">
17 window["undefined"] = window["undefined"];
21 * Roo core utilities and functions.
26 * Copies all the properties of config to obj.
27 * @param {Object} obj The receiver of the properties
28 * @param {Object} config The source of the properties
29 * @param {Object} defaults A different object that will also be applied for default values
30 * @return {Object} returns obj
35 Roo.apply = function(o, c, defaults){
37 // no "this" reference for friendly out of scope calls
38 Roo.apply(o, defaults);
40 if(o && c && typeof c == 'object'){
51 var ua = navigator.userAgent.toLowerCase();
53 var isStrict = document.compatMode == "CSS1Compat",
54 isOpera = ua.indexOf("opera") > -1,
55 isSafari = (/webkit|khtml/).test(ua),
56 isFirefox = ua.indexOf("firefox") > -1,
57 isIE = ua.indexOf("msie") > -1,
58 isIE7 = ua.indexOf("msie 7") > -1,
59 isIE11 = /trident.*rv\:11\./.test(ua),
60 isEdge = ua.indexOf("edge") > -1,
61 isGecko = !isSafari && ua.indexOf("gecko") > -1,
62 isBorderBox = isIE && !isStrict,
63 isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
64 isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
65 isLinux = (ua.indexOf("linux") != -1),
66 isSecure = window.location.href.toLowerCase().indexOf("https") === 0,
67 isIOS = /iphone|ipad/.test(ua),
68 isAndroid = /android/.test(ua),
69 isTouch = (function() {
71 if (ua.indexOf('chrome') != -1 && ua.indexOf('android') == -1) {
72 window.addEventListener('touchstart', function __set_has_touch__ () {
74 window.removeEventListener('touchstart', __set_has_touch__);
76 return false; // no touch on chrome!?
78 document.createEvent("TouchEvent");
85 // remove css image flicker
88 document.execCommand("BackgroundImageCache", false, true);
94 * True if the browser is in strict mode
99 * True if the page is running over SSL
104 * True when the document is fully initialized and ready for action
109 * Turn on debugging output (currently only the factory uses this)
116 * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
119 enableGarbageCollector : true,
122 * True to automatically purge event listeners after uncaching an element (defaults to false).
123 * Note: this only happens if enableGarbageCollector is true.
126 enableListenerCollection:false,
129 * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
130 * the IE insecure content warning (defaults to javascript:false).
133 SSL_SECURE_URL : "javascript:false",
136 * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
137 * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
140 BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
142 emptyFn : function(){},
145 * Copies all the properties of config to obj if they don't already exist.
146 * @param {Object} obj The receiver of the properties
147 * @param {Object} config The source of the properties
148 * @return {Object} returns obj
150 applyIf : function(o, c){
153 if(typeof o[p] == "undefined"){ o[p] = c[p]; }
160 * Applies event listeners to elements by selectors when the document is ready.
161 * The event name is specified with an @ suffix.
164 // add a listener for click on all anchors in element with id foo
165 '#foo a@click' : function(e, t){
169 // add the same listener to multiple selectors (separated by comma BEFORE the @)
170 '#foo a, #bar span.some-class@mouseover' : function(){
175 * @param {Object} obj The list of behaviors to apply
177 addBehaviors : function(o){
179 Roo.onReady(function(){
184 var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
186 var parts = b.split('@');
187 if(parts[1]){ // for Object prototype breakers
190 cache[s] = Roo.select(s);
192 cache[s].on(parts[1], o[b]);
199 * Generates unique ids. If the element already has an id, it is unchanged
200 * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
201 * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
202 * @return {String} The generated Id.
204 id : function(el, prefix){
205 prefix = prefix || "roo-gen";
207 var id = prefix + (++idSeed);
208 return el ? (el.id ? el.id : (el.id = id)) : id;
213 * Extends one class with another class and optionally overrides members with the passed literal. This class
214 * also adds the function "override()" to the class that can be used to override
215 * members on an instance.
216 * @param {Object} subclass The class inheriting the functionality
217 * @param {Object} superclass The class being extended
218 * @param {Object} overrides (optional) A literal with members
223 var io = function(o){
228 return function(sb, sp, overrides){
229 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
232 sb = function(){sp.apply(this, arguments);};
234 var F = function(){}, sbp, spp = sp.prototype;
236 sbp = sb.prototype = new F();
240 if(spp.constructor == Object.prototype.constructor){
245 sb.override = function(o){
249 Roo.override(sb, overrides);
255 * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
257 Roo.override(MyClass, {
258 newMethod1: function(){
261 newMethod2: function(foo){
266 * @param {Object} origclass The class to override
267 * @param {Object} overrides The list of functions to add to origClass. This should be specified as an object literal
268 * containing one or more methods.
271 override : function(origclass, overrides){
273 var p = origclass.prototype;
274 for(var method in overrides){
275 p[method] = overrides[method];
280 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
282 Roo.namespace('Company', 'Company.data');
283 Company.Widget = function() { ... }
284 Company.data.CustomStore = function(config) { ... }
286 * @param {String} namespace1
287 * @param {String} namespace2
288 * @param {String} etc
291 namespace : function(){
292 var a=arguments, o=null, i, j, d, rt;
293 for (i=0; i<a.length; ++i) {
297 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
298 for (j=1; j<d.length; ++j) {
299 o[d[j]]=o[d[j]] || {};
305 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
307 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
308 Roo.factory(conf, Roo.data);
310 * @param {String} classname
311 * @param {String} namespace (optional)
315 factory : function(c, ns)
317 // no xtype, no ns or c.xns - or forced off by c.xns
318 if (!c.xtype || (!ns && !c.xns) || (c.xns === false)) { // not enough info...
321 ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
322 if (c.constructor == ns[c.xtype]) {// already created...
326 if (Roo.debug) { Roo.log("Roo.Factory(" + c.xtype + ")"); }
327 var ret = new ns[c.xtype](c);
331 c.xns = false; // prevent recursion..
335 * Logs to console if it can.
337 * @param {String|Object} string
342 if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
349 * Takes an object and converts it to an encoded URL. e.g. Roo.urlEncode({foo: 1, bar: 2}); would return "foo=1&bar=2". Optionally, property values can be arrays, instead of keys and the resulting string that's returned will contain a name/value pair for each array value.
353 urlEncode : function(o){
359 var ov = o[key], k = Roo.encodeURIComponent(key);
360 var type = typeof ov;
361 if(type == 'undefined'){
363 }else if(type != "function" && type != "object"){
364 buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
365 }else if(ov instanceof Array){
367 for(var i = 0, len = ov.length; i < len; i++) {
368 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
379 * Safe version of encodeURIComponent
380 * @param {String} data
384 encodeURIComponent : function (data)
387 return encodeURIComponent(data);
388 } catch(e) {} // should be an uri encode error.
390 if (data == '' || data == null){
393 // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
394 function nibble_to_hex(nibble){
395 var chars = '0123456789ABCDEF';
396 return chars.charAt(nibble);
398 data = data.toString();
400 for(var i=0; i<data.length; i++){
401 var c = data.charCodeAt(i);
402 var bs = new Array();
405 bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
406 bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
407 bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
408 bs[3] = 0x80 | (c & 0x3F);
409 }else if (c > 0x800){
411 bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
412 bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
413 bs[2] = 0x80 | (c & 0x3F);
416 bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
417 bs[1] = 0x80 | (c & 0x3F);
422 for(var j=0; j<bs.length; j++){
424 var hex = nibble_to_hex((b & 0xF0) >>> 4)
425 + nibble_to_hex(b &0x0F);
434 * Takes an encoded URL and and converts it to an object. e.g. Roo.urlDecode("foo=1&bar=2"); would return {foo: 1, bar: 2} or Roo.urlDecode("foo=1&bar=2&bar=3&bar=4", true); would return {foo: 1, bar: [2, 3, 4]}.
435 * @param {String} string
436 * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
437 * @return {Object} A literal with members
439 urlDecode : function(string, overwrite){
440 if(!string || !string.length){
444 var pairs = string.split('&');
445 var pair, name, value;
446 for(var i = 0, len = pairs.length; i < len; i++){
447 pair = pairs[i].split('=');
448 name = decodeURIComponent(pair[0]);
449 value = decodeURIComponent(pair[1]);
450 if(overwrite !== true){
451 if(typeof obj[name] == "undefined"){
453 }else if(typeof obj[name] == "string"){
454 obj[name] = [obj[name]];
455 obj[name].push(value);
457 obj[name].push(value);
467 * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
468 * passed array is not really an array, your function is called once with it.
469 * The supplied function is called with (Object item, Number index, Array allItems).
470 * @param {Array/NodeList/Mixed} array
471 * @param {Function} fn
472 * @param {Object} scope
474 each : function(array, fn, scope){
475 if(typeof array.length == "undefined" || typeof array == "string"){
478 for(var i = 0, len = array.length; i < len; i++){
479 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
484 combine : function(){
485 var as = arguments, l = as.length, r = [];
486 for(var i = 0; i < l; i++){
488 if(a instanceof Array){
490 }else if(a.length !== undefined && !a.substr){
491 r = r.concat(Array.prototype.slice.call(a, 0));
500 * Escapes the passed string for use in a regular expression
501 * @param {String} str
504 escapeRe : function(s) {
505 return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
509 callback : function(cb, scope, args, delay){
510 if(typeof cb == "function"){
512 cb.defer(delay, scope, args || []);
514 cb.apply(scope, args || []);
520 * Return the dom node for the passed string (id), dom node, or Roo.Element
521 * @param {String/HTMLElement/Roo.Element} el
522 * @return HTMLElement
524 getDom : function(el){
528 return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
532 * Shorthand for {@link Roo.ComponentMgr#get}
534 * @return Roo.Component
536 getCmp : function(id){
537 return Roo.ComponentMgr.get(id);
540 num : function(v, defaultValue){
541 if(typeof v != 'number'){
547 destroy : function(){
548 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
552 as.removeAllListeners();
556 if(typeof as.purgeListeners == 'function'){
559 if(typeof as.destroy == 'function'){
566 // inpired by a similar function in mootools library
568 * Returns the type of object that is passed in. If the object passed in is null or undefined it
569 * return false otherwise it returns one of the following values:<ul>
570 * <li><b>string</b>: If the object passed is a string</li>
571 * <li><b>number</b>: If the object passed is a number</li>
572 * <li><b>boolean</b>: If the object passed is a boolean value</li>
573 * <li><b>function</b>: If the object passed is a function reference</li>
574 * <li><b>object</b>: If the object passed is an object</li>
575 * <li><b>array</b>: If the object passed is an array</li>
576 * <li><b>regexp</b>: If the object passed is a regular expression</li>
577 * <li><b>element</b>: If the object passed is a DOM Element</li>
578 * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
579 * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
580 * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
581 * @param {Mixed} object
585 if(o === undefined || o === null){
592 if(t == 'object' && o.nodeName) {
594 case 1: return 'element';
595 case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
598 if(t == 'object' || t == 'function') {
599 switch(o.constructor) {
600 case Array: return 'array';
601 case RegExp: return 'regexp';
603 if(typeof o.length == 'number' && typeof o.item == 'function') {
611 * Returns true if the passed value is null, undefined or an empty string (optional).
612 * @param {Mixed} value The value to test
613 * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
616 isEmpty : function(v, allowBlank){
617 return v === null || v === undefined || (!allowBlank ? v === '' : false);
625 isFirefox : isFirefox,
637 isBorderBox : isBorderBox,
639 isWindows : isWindows,
647 isAndroid : isAndroid,
652 * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
653 * you may want to set this to true.
656 useShims : ((isIE && !isIE7) || (isGecko && isMac)),
661 * Selects a single element as a Roo Element
662 * This is about as close as you can get to jQuery's $('do crazy stuff')
663 * @param {String} selector The selector/xpath query
664 * @param {Node} root (optional) The start of the query (defaults to document).
665 * @return {Roo.Element}
667 selectNode : function(selector, root)
669 var node = Roo.DomQuery.selectNode(selector,root);
670 return node ? Roo.get(node) : new Roo.Element(false);
673 * Find the current bootstrap width Grid size
674 * Note xs is the default for smaller.. - this is currently used by grids to render correct columns
675 * @returns {String} (xs|sm|md|lg|xl)
678 getGridSize : function()
680 var w = Roo.lib.Dom.getViewWidth();
701 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
702 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout",
705 "Roo.bootstrap.dash");
708 * Ext JS Library 1.1.1
709 * Copyright(c) 2006-2007, Ext JS, LLC.
711 * Originally Released Under LGPL - original licence link has changed is not relivant.
714 * <script type="text/javascript">
718 // wrappedn so fnCleanup is not in global scope...
720 function fnCleanUp() {
721 var p = Function.prototype;
722 delete p.createSequence;
724 delete p.createDelegate;
725 delete p.createCallback;
726 delete p.createInterceptor;
728 window.detachEvent("onunload", fnCleanUp);
730 window.attachEvent("onunload", fnCleanUp);
737 * These functions are available on every Function object (any JavaScript function).
739 Roo.apply(Function.prototype, {
741 * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
742 * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
743 * Will create a function that is bound to those 2 args.
744 * @return {Function} The new function
746 createCallback : function(/*args...*/){
747 // make args available, in function below
748 var args = arguments;
751 return method.apply(window, args);
756 * Creates a delegate (callback) that sets the scope to obj.
757 * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
758 * Will create a function that is automatically scoped to this.
759 * @param {Object} obj (optional) The object for which the scope is set
760 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
761 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
762 * if a number the args are inserted at the specified position
763 * @return {Function} The new function
765 createDelegate : function(obj, args, appendArgs){
768 var callArgs = args || arguments;
769 if(appendArgs === true){
770 callArgs = Array.prototype.slice.call(arguments, 0);
771 callArgs = callArgs.concat(args);
772 }else if(typeof appendArgs == "number"){
773 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
774 var applyArgs = [appendArgs, 0].concat(args); // create method call params
775 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
777 return method.apply(obj || window, callArgs);
782 * Calls this function after the number of millseconds specified.
783 * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
784 * @param {Object} obj (optional) The object for which the scope is set
785 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
786 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
787 * if a number the args are inserted at the specified position
788 * @return {Number} The timeout id that can be used with clearTimeout
790 defer : function(millis, obj, args, appendArgs){
791 var fn = this.createDelegate(obj, args, appendArgs);
793 return setTimeout(fn, millis);
799 * Create a combined function call sequence of the original function + the passed function.
800 * The resulting function returns the results of the original function.
801 * The passed fcn is called with the parameters of the original function
802 * @param {Function} fcn The function to sequence
803 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
804 * @return {Function} The new function
806 createSequence : function(fcn, scope){
807 if(typeof fcn != "function"){
812 var retval = method.apply(this || window, arguments);
813 fcn.apply(scope || this || window, arguments);
819 * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
820 * The resulting function returns the results of the original function.
821 * The passed fcn is called with the parameters of the original function.
823 * @param {Function} fcn The function to call before the original
824 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
825 * @return {Function} The new function
827 createInterceptor : function(fcn, scope){
828 if(typeof fcn != "function"){
835 if(fcn.apply(scope || this || window, arguments) === false){
838 return method.apply(this || window, arguments);
844 * Ext JS Library 1.1.1
845 * Copyright(c) 2006-2007, Ext JS, LLC.
847 * Originally Released Under LGPL - original licence link has changed is not relivant.
850 * <script type="text/javascript">
853 Roo.applyIf(String, {
858 * Escapes the passed string for ' and \
859 * @param {String} string The string to escape
860 * @return {String} The escaped string
863 escape : function(string) {
864 return string.replace(/('|\\)/g, "\\$1");
868 * Pads the left side of a string with a specified character. This is especially useful
869 * for normalizing number and date strings. Example usage:
871 var s = String.leftPad('123', 5, '0');
872 // s now contains the string: '00123'
874 * @param {String} string The original string
875 * @param {Number} size The total length of the output string
876 * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
877 * @return {String} The padded string
880 leftPad : function (val, size, ch) {
881 var result = new String(val);
882 if(ch === null || ch === undefined || ch === '') {
885 while (result.length < size) {
886 result = ch + result;
892 * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens. Each
893 * token must be unique, and must increment in the format {0}, {1}, etc. Example usage:
895 var cls = 'my-class', text = 'Some text';
896 var s = String.format('<div class="{0}">{1}</div>', cls, text);
897 // s now contains the string: '<div class="my-class">Some text</div>'
899 * @param {String} string The tokenized string to be formatted
900 * @param {String} value1 The value to replace token {0}
901 * @param {String} value2 Etc...
902 * @return {String} The formatted string
905 format : function(format){
906 var args = Array.prototype.slice.call(arguments, 1);
907 return format.replace(/\{(\d+)\}/g, function(m, i){
908 return Roo.util.Format.htmlEncode(args[i]);
916 * Utility function that allows you to easily switch a string between two alternating values. The passed value
917 * is compared to the current string, and if they are equal, the other value that was passed in is returned. If
918 * they are already different, the first value passed in is returned. Note that this method returns the new value
919 * but does not change the current string.
921 // alternate sort directions
922 sort = sort.toggle('ASC', 'DESC');
924 // instead of conditional logic:
925 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
927 * @param {String} value The value to compare to the current string
928 * @param {String} other The new value to use if the string already equals the first value passed in
929 * @return {String} The new value
932 String.prototype.toggle = function(value, other){
933 return this == value ? other : value;
938 * Remove invalid unicode characters from a string
940 * @return {String} The clean string
942 String.prototype.unicodeClean = function () {
943 return this.replace(/[\s\S]/g,
944 function(character) {
945 if (character.charCodeAt()< 256) {
949 encodeURIComponent(character);
960 * Ext JS Library 1.1.1
961 * Copyright(c) 2006-2007, Ext JS, LLC.
963 * Originally Released Under LGPL - original licence link has changed is not relivant.
966 * <script type="text/javascript">
972 Roo.applyIf(Number.prototype, {
974 * Checks whether or not the current number is within a desired range. If the number is already within the
975 * range it is returned, otherwise the min or max value is returned depending on which side of the range is
976 * exceeded. Note that this method returns the constrained value but does not change the current number.
977 * @param {Number} min The minimum number in the range
978 * @param {Number} max The maximum number in the range
979 * @return {Number} The constrained value if outside the range, otherwise the current value
981 constrain : function(min, max){
982 return Math.min(Math.max(this, min), max);
986 * Ext JS Library 1.1.1
987 * Copyright(c) 2006-2007, Ext JS, LLC.
989 * Originally Released Under LGPL - original licence link has changed is not relivant.
992 * <script type="text/javascript">
997 Roo.applyIf(Array.prototype, {
1000 * Checks whether or not the specified object exists in the array.
1001 * @param {Object} o The object to check for
1002 * @return {Number} The index of o in the array (or -1 if it is not found)
1004 indexOf : function(o){
1005 for (var i = 0, len = this.length; i < len; i++){
1006 if(this[i] == o) { return i; }
1012 * Removes the specified object from the array. If the object is not found nothing happens.
1013 * @param {Object} o The object to remove
1015 remove : function(o){
1016 var index = this.indexOf(o);
1018 this.splice(index, 1);
1022 * Map (JS 1.6 compatibility)
1023 * @param {Function} function to call
1025 map : function(fun )
1027 var len = this.length >>> 0;
1028 if (typeof fun != "function") {
1029 throw new TypeError();
1031 var res = new Array(len);
1032 var thisp = arguments[1];
1033 for (var i = 0; i < len; i++)
1036 res[i] = fun.call(thisp, this[i], i, this);
1044 * @param {Array} o The array to compare to
1045 * @returns {Boolean} true if the same
1047 equals : function(b)
1049 // https://stackoverflow.com/questions/3115982/how-to-check-if-two-arrays-are-equal-with-javascript
1056 if (this.length !== b.length) {
1060 // sort?? a.sort().equals(b.sort());
1062 for (var i = 0; i < this.length; ++i) {
1063 if (this[i] !== b[i]) {
1075 * Ext JS Library 1.1.1
1076 * Copyright(c) 2006-2007, Ext JS, LLC.
1078 * Originally Released Under LGPL - original licence link has changed is not relivant.
1081 * <script type="text/javascript">
1087 * The date parsing and format syntax is a subset of
1088 * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
1089 * supported will provide results equivalent to their PHP versions.
1091 * Following is the list of all currently supported formats:
1094 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
1096 Format Output Description
1097 ------ ---------- --------------------------------------------------------------
1098 d 10 Day of the month, 2 digits with leading zeros
1099 D Wed A textual representation of a day, three letters
1100 j 10 Day of the month without leading zeros
1101 l Wednesday A full textual representation of the day of the week
1102 S th English ordinal day of month suffix, 2 chars (use with j)
1103 w 3 Numeric representation of the day of the week
1104 z 9 The julian date, or day of the year (0-365)
1105 W 01 ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
1106 F January A full textual representation of the month
1107 m 01 Numeric representation of a month, with leading zeros
1108 M Jan Month name abbreviation, three letters
1109 n 1 Numeric representation of a month, without leading zeros
1110 t 31 Number of days in the given month
1111 L 0 Whether it's a leap year (1 if it is a leap year, else 0)
1112 Y 2007 A full numeric representation of a year, 4 digits
1113 y 07 A two digit representation of a year
1114 a pm Lowercase Ante meridiem and Post meridiem
1115 A PM Uppercase Ante meridiem and Post meridiem
1116 g 3 12-hour format of an hour without leading zeros
1117 G 15 24-hour format of an hour without leading zeros
1118 h 03 12-hour format of an hour with leading zeros
1119 H 15 24-hour format of an hour with leading zeros
1120 i 05 Minutes with leading zeros
1121 s 01 Seconds, with leading zeros
1122 O -0600 Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1123 P -06:00 Difference to Greenwich time (GMT) with colon between hours and minutes
1124 T CST Timezone setting of the machine running the code
1125 Z -21600 Timezone offset in seconds (negative if west of UTC, positive if east)
1128 * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1130 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1131 document.write(dt.format('Y-m-d')); //2007-01-10
1132 document.write(dt.format('F j, Y, g:i a')); //January 10, 2007, 3:05 pm
1133 document.write(dt.format('l, \\t\\he dS of F Y h:i:s A')); //Wednesday, the 10th of January 2007 03:05:01 PM
1136 * Here are some standard date/time patterns that you might find helpful. They
1137 * are not part of the source of Date.js, but to use them you can simply copy this
1138 * block of code into any script that is included after Date.js and they will also become
1139 * globally available on the Date object. Feel free to add or remove patterns as needed in your code.
1142 ISO8601Long:"Y-m-d H:i:s",
1143 ISO8601Short:"Y-m-d",
1145 LongDate: "l, F d, Y",
1146 FullDateTime: "l, F d, Y g:i:s A",
1149 LongTime: "g:i:s A",
1150 SortableDateTime: "Y-m-d\\TH:i:s",
1151 UniversalSortableDateTime: "Y-m-d H:i:sO",
1158 var dt = new Date();
1159 document.write(dt.format(Date.patterns.ShortDate));
1164 * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1165 * They generate precompiled functions from date formats instead of parsing and
1166 * processing the pattern every time you format a date. These functions are available
1167 * on every Date object (any javascript function).
1169 * The original article and download are here:
1170 * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1177 Returns the number of milliseconds between this date and date
1178 @param {Date} date (optional) Defaults to now
1179 @return {Number} The diff in milliseconds
1180 @member Date getElapsed
1182 Date.prototype.getElapsed = function(date) {
1183 return Math.abs((date || new Date()).getTime()-this.getTime());
1185 // was in date file..
1189 Date.parseFunctions = {count:0};
1191 Date.parseRegexes = [];
1193 Date.formatFunctions = {count:0};
1196 Date.prototype.dateFormat = function(format) {
1197 if (Date.formatFunctions[format] == null) {
1198 Date.createNewFormat(format);
1200 var func = Date.formatFunctions[format];
1201 return this[func]();
1206 * Formats a date given the supplied format string
1207 * @param {String} format The format string
1208 * @return {String} The formatted date
1211 Date.prototype.format = Date.prototype.dateFormat;
1214 Date.createNewFormat = function(format) {
1215 var funcName = "format" + Date.formatFunctions.count++;
1216 Date.formatFunctions[format] = funcName;
1217 var code = "Date.prototype." + funcName + " = function(){return ";
1218 var special = false;
1220 for (var i = 0; i < format.length; ++i) {
1221 ch = format.charAt(i);
1222 if (!special && ch == "\\") {
1227 code += "'" + String.escape(ch) + "' + ";
1230 code += Date.getFormatCode(ch);
1233 /** eval:var:zzzzzzzzzzzzz */
1234 eval(code.substring(0, code.length - 3) + ";}");
1238 Date.getFormatCode = function(character) {
1239 switch (character) {
1241 return "String.leftPad(this.getDate(), 2, '0') + ";
1243 return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1245 return "this.getDate() + ";
1247 return "Date.dayNames[this.getDay()] + ";
1249 return "this.getSuffix() + ";
1251 return "this.getDay() + ";
1253 return "this.getDayOfYear() + ";
1255 return "this.getWeekOfYear() + ";
1257 return "Date.monthNames[this.getMonth()] + ";
1259 return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1261 return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1263 return "(this.getMonth() + 1) + ";
1265 return "this.getDaysInMonth() + ";
1267 return "(this.isLeapYear() ? 1 : 0) + ";
1269 return "this.getFullYear() + ";
1271 return "('' + this.getFullYear()).substring(2, 4) + ";
1273 return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1275 return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1277 return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1279 return "this.getHours() + ";
1281 return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1283 return "String.leftPad(this.getHours(), 2, '0') + ";
1285 return "String.leftPad(this.getMinutes(), 2, '0') + ";
1287 return "String.leftPad(this.getSeconds(), 2, '0') + ";
1289 return "this.getGMTOffset() + ";
1291 return "this.getGMTColonOffset() + ";
1293 return "this.getTimezone() + ";
1295 return "(this.getTimezoneOffset() * -60) + ";
1297 return "'" + String.escape(character) + "' + ";
1302 * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1303 * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates. Any part of
1304 * the date format that is not specified will default to the current date value for that part. Time parts can also
1305 * be specified, but default to 0. Keep in mind that the input date string must precisely match the specified format
1306 * string or the parse operation will fail.
1309 //dt = Fri May 25 2007 (current date)
1310 var dt = new Date();
1312 //dt = Thu May 25 2006 (today's month/day in 2006)
1313 dt = Date.parseDate("2006", "Y");
1315 //dt = Sun Jan 15 2006 (all date parts specified)
1316 dt = Date.parseDate("2006-1-15", "Y-m-d");
1318 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1319 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1321 * @param {String} input The unparsed date as a string
1322 * @param {String} format The format the date is in
1323 * @return {Date} The parsed date
1326 Date.parseDate = function(input, format) {
1327 if (Date.parseFunctions[format] == null) {
1328 Date.createParser(format);
1330 var func = Date.parseFunctions[format];
1331 return Date[func](input);
1337 Date.createParser = function(format) {
1338 var funcName = "parse" + Date.parseFunctions.count++;
1339 var regexNum = Date.parseRegexes.length;
1340 var currentGroup = 1;
1341 Date.parseFunctions[format] = funcName;
1343 var code = "Date." + funcName + " = function(input){\n"
1344 + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1345 + "var d = new Date();\n"
1346 + "y = d.getFullYear();\n"
1347 + "m = d.getMonth();\n"
1348 + "d = d.getDate();\n"
1349 + "if (typeof(input) !== 'string') { input = input.toString(); }\n"
1350 + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1351 + "if (results && results.length > 0) {";
1354 var special = false;
1356 for (var i = 0; i < format.length; ++i) {
1357 ch = format.charAt(i);
1358 if (!special && ch == "\\") {
1363 regex += String.escape(ch);
1366 var obj = Date.formatCodeToRegex(ch, currentGroup);
1367 currentGroup += obj.g;
1369 if (obj.g && obj.c) {
1375 code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1376 + "{v = new Date(y, m, d, h, i, s);}\n"
1377 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1378 + "{v = new Date(y, m, d, h, i);}\n"
1379 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1380 + "{v = new Date(y, m, d, h);}\n"
1381 + "else if (y >= 0 && m >= 0 && d > 0)\n"
1382 + "{v = new Date(y, m, d);}\n"
1383 + "else if (y >= 0 && m >= 0)\n"
1384 + "{v = new Date(y, m);}\n"
1385 + "else if (y >= 0)\n"
1386 + "{v = new Date(y);}\n"
1387 + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1388 + " ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1389 + " v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1392 Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1393 /** eval:var:zzzzzzzzzzzzz */
1398 Date.formatCodeToRegex = function(character, currentGroup) {
1399 switch (character) {
1403 s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1406 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1407 s:"(\\d{1,2})"}; // day of month without leading zeroes
1410 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1411 s:"(\\d{2})"}; // day of month with leading zeroes
1415 s:"(?:" + Date.dayNames.join("|") + ")"};
1419 s:"(?:st|nd|rd|th)"};
1434 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1435 s:"(" + Date.monthNames.join("|") + ")"};
1438 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1439 s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1442 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1443 s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1446 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1447 s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1458 c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1462 c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1463 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1467 c:"if (results[" + currentGroup + "] == 'am') {\n"
1468 + "if (h == 12) { h = 0; }\n"
1469 + "} else { if (h < 12) { h += 12; }}",
1473 c:"if (results[" + currentGroup + "] == 'AM') {\n"
1474 + "if (h == 12) { h = 0; }\n"
1475 + "} else { if (h < 12) { h += 12; }}",
1480 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1481 s:"(\\d{1,2})"}; // 12/24-hr format format of an hour without leading zeroes
1485 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1486 s:"(\\d{2})"}; // 12/24-hr format format of an hour with leading zeroes
1489 c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1493 c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1498 "o = results[", currentGroup, "];\n",
1499 "var sn = o.substring(0,1);\n", // get + / - sign
1500 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1501 "var mn = o.substring(3,5) % 60;\n", // get minutes
1502 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1503 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1505 s:"([+\-]\\d{2,4})"};
1511 "o = results[", currentGroup, "];\n",
1512 "var sn = o.substring(0,1);\n",
1513 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1514 "var mn = o.substring(4,6) % 60;\n",
1515 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1516 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1522 s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1525 c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1526 + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1527 s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1531 s:String.escape(character)};
1536 * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1537 * @return {String} The abbreviated timezone name (e.g. 'CST')
1539 Date.prototype.getTimezone = function() {
1540 return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1544 * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1545 * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1547 Date.prototype.getGMTOffset = function() {
1548 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1549 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1550 + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1554 * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1555 * @return {String} 2-characters representing hours and 2-characters representing minutes
1556 * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1558 Date.prototype.getGMTColonOffset = function() {
1559 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1560 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1562 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1566 * Get the numeric day number of the year, adjusted for leap year.
1567 * @return {Number} 0 through 364 (365 in leap years)
1569 Date.prototype.getDayOfYear = function() {
1571 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1572 for (var i = 0; i < this.getMonth(); ++i) {
1573 num += Date.daysInMonth[i];
1575 return num + this.getDate() - 1;
1579 * Get the string representation of the numeric week number of the year
1580 * (equivalent to the format specifier 'W').
1581 * @return {String} '00' through '52'
1583 Date.prototype.getWeekOfYear = function() {
1584 // Skip to Thursday of this week
1585 var now = this.getDayOfYear() + (4 - this.getDay());
1586 // Find the first Thursday of the year
1587 var jan1 = new Date(this.getFullYear(), 0, 1);
1588 var then = (7 - jan1.getDay() + 4);
1589 return String.leftPad(((now - then) / 7) + 1, 2, "0");
1593 * Whether or not the current date is in a leap year.
1594 * @return {Boolean} True if the current date is in a leap year, else false
1596 Date.prototype.isLeapYear = function() {
1597 var year = this.getFullYear();
1598 return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1602 * Get the first day of the current month, adjusted for leap year. The returned value
1603 * is the numeric day index within the week (0-6) which can be used in conjunction with
1604 * the {@link #monthNames} array to retrieve the textual day name.
1607 var dt = new Date('1/10/2007');
1608 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1610 * @return {Number} The day number (0-6)
1612 Date.prototype.getFirstDayOfMonth = function() {
1613 var day = (this.getDay() - (this.getDate() - 1)) % 7;
1614 return (day < 0) ? (day + 7) : day;
1618 * Get the last day of the current month, adjusted for leap year. The returned value
1619 * is the numeric day index within the week (0-6) which can be used in conjunction with
1620 * the {@link #monthNames} array to retrieve the textual day name.
1623 var dt = new Date('1/10/2007');
1624 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1626 * @return {Number} The day number (0-6)
1628 Date.prototype.getLastDayOfMonth = function() {
1629 var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1630 return (day < 0) ? (day + 7) : day;
1635 * Get the first date of this date's month
1638 Date.prototype.getFirstDateOfMonth = function() {
1639 return new Date(this.getFullYear(), this.getMonth(), 1);
1643 * Get the last date of this date's month
1646 Date.prototype.getLastDateOfMonth = function() {
1647 return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1650 * Get the number of days in the current month, adjusted for leap year.
1651 * @return {Number} The number of days in the month
1653 Date.prototype.getDaysInMonth = function() {
1654 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1655 return Date.daysInMonth[this.getMonth()];
1659 * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1660 * @return {String} 'st, 'nd', 'rd' or 'th'
1662 Date.prototype.getSuffix = function() {
1663 switch (this.getDate()) {
1680 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1683 * An array of textual month names.
1684 * Override these values for international dates, for example...
1685 * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1704 * An array of textual day names.
1705 * Override these values for international dates, for example...
1706 * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1722 Date.monthNumbers = {
1737 * Creates and returns a new Date instance with the exact same date value as the called instance.
1738 * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1739 * variable will also be changed. When the intention is to create a new variable that will not
1740 * modify the original instance, you should create a clone.
1742 * Example of correctly cloning a date:
1745 var orig = new Date('10/1/2006');
1748 document.write(orig); //returns 'Thu Oct 05 2006'!
1751 var orig = new Date('10/1/2006');
1752 var copy = orig.clone();
1754 document.write(orig); //returns 'Thu Oct 01 2006'
1756 * @return {Date} The new Date instance
1758 Date.prototype.clone = function() {
1759 return new Date(this.getTime());
1763 * Clears any time information from this date
1764 @param {Boolean} clone true to create a clone of this date, clear the time and return it
1765 @return {Date} this or the clone
1767 Date.prototype.clearTime = function(clone){
1769 return this.clone().clearTime();
1774 this.setMilliseconds(0);
1779 // safari setMonth is broken -- check that this is only donw once...
1780 if(Roo.isSafari && typeof(Date.brokenSetMonth) == 'undefined'){
1781 Date.brokenSetMonth = Date.prototype.setMonth;
1782 Date.prototype.setMonth = function(num){
1784 var n = Math.ceil(-num);
1785 var back_year = Math.ceil(n/12);
1786 var month = (n % 12) ? 12 - n % 12 : 0 ;
1787 this.setFullYear(this.getFullYear() - back_year);
1788 return Date.brokenSetMonth.call(this, month);
1790 return Date.brokenSetMonth.apply(this, arguments);
1795 /** Date interval constant
1799 /** Date interval constant
1803 /** Date interval constant
1807 /** Date interval constant
1811 /** Date interval constant
1815 /** Date interval constant
1819 /** Date interval constant
1825 * Provides a convenient method of performing basic date arithmetic. This method
1826 * does not modify the Date instance being called - it creates and returns
1827 * a new Date instance containing the resulting date value.
1832 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1833 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1835 //Negative values will subtract correctly:
1836 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1837 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1839 //You can even chain several calls together in one line!
1840 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1841 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1844 * @param {String} interval A valid date interval enum value
1845 * @param {Number} value The amount to add to the current date
1846 * @return {Date} The new Date instance
1848 Date.prototype.add = function(interval, value){
1849 var d = this.clone();
1850 if (!interval || value === 0) { return d; }
1851 switch(interval.toLowerCase()){
1853 d.setMilliseconds(this.getMilliseconds() + value);
1856 d.setSeconds(this.getSeconds() + value);
1859 d.setMinutes(this.getMinutes() + value);
1862 d.setHours(this.getHours() + value);
1865 d.setDate(this.getDate() + value);
1868 var day = this.getDate();
1870 day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1873 d.setMonth(this.getMonth() + value);
1876 d.setFullYear(this.getFullYear() + value);
1883 * Ext JS Library 1.1.1
1884 * Copyright(c) 2006-2007, Ext JS, LLC.
1886 * Originally Released Under LGPL - original licence link has changed is not relivant.
1889 * <script type="text/javascript">
1893 * @class Roo.lib.Dom
1896 * Dom utils (from YIU afaik)
1901 * Get the view width
1902 * @param {Boolean} full True will get the full document, otherwise it's the view width
1903 * @return {Number} The width
1906 getViewWidth : function(full) {
1907 return full ? this.getDocumentWidth() : this.getViewportWidth();
1910 * Get the view height
1911 * @param {Boolean} full True will get the full document, otherwise it's the view height
1912 * @return {Number} The height
1914 getViewHeight : function(full) {
1915 return full ? this.getDocumentHeight() : this.getViewportHeight();
1918 getDocumentHeight: function() {
1919 var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1920 return Math.max(scrollHeight, this.getViewportHeight());
1923 getDocumentWidth: function() {
1924 var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1925 return Math.max(scrollWidth, this.getViewportWidth());
1928 getViewportHeight: function() {
1929 var height = self.innerHeight;
1930 var mode = document.compatMode;
1932 if ((mode || Roo.isIE) && !Roo.isOpera) {
1933 height = (mode == "CSS1Compat") ?
1934 document.documentElement.clientHeight :
1935 document.body.clientHeight;
1941 getViewportWidth: function() {
1942 var width = self.innerWidth;
1943 var mode = document.compatMode;
1945 if (mode || Roo.isIE) {
1946 width = (mode == "CSS1Compat") ?
1947 document.documentElement.clientWidth :
1948 document.body.clientWidth;
1953 isAncestor : function(p, c) {
1960 if (p.contains && !Roo.isSafari) {
1961 return p.contains(c);
1962 } else if (p.compareDocumentPosition) {
1963 return !!(p.compareDocumentPosition(c) & 16);
1965 var parent = c.parentNode;
1970 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1973 parent = parent.parentNode;
1979 getRegion : function(el) {
1980 return Roo.lib.Region.getRegion(el);
1983 getY : function(el) {
1984 return this.getXY(el)[1];
1987 getX : function(el) {
1988 return this.getXY(el)[0];
1991 getXY : function(el) {
1992 var p, pe, b, scroll, bd = document.body;
1993 el = Roo.getDom(el);
1994 var fly = Roo.lib.AnimBase.fly;
1995 if (el.getBoundingClientRect) {
1996 b = el.getBoundingClientRect();
1997 scroll = fly(document).getScroll();
1998 return [b.left + scroll.left, b.top + scroll.top];
2004 var hasAbsolute = fly(el).getStyle("position") == "absolute";
2011 if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
2018 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
2019 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
2026 if (p != el && pe.getStyle('overflow') != 'visible') {
2034 if (Roo.isSafari && hasAbsolute) {
2039 if (Roo.isGecko && !hasAbsolute) {
2041 x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
2042 y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
2046 while (p && p != bd) {
2047 if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
2059 setXY : function(el, xy) {
2060 el = Roo.fly(el, '_setXY');
2062 var pts = el.translatePoints(xy);
2063 if (xy[0] !== false) {
2064 el.dom.style.left = pts.left + "px";
2066 if (xy[1] !== false) {
2067 el.dom.style.top = pts.top + "px";
2071 setX : function(el, x) {
2072 this.setXY(el, [x, false]);
2075 setY : function(el, y) {
2076 this.setXY(el, [false, y]);
2080 * Portions of this file are based on pieces of Yahoo User Interface Library
2081 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2082 * YUI licensed under the BSD License:
2083 * http://developer.yahoo.net/yui/license.txt
2084 * <script type="text/javascript">
2088 Roo.lib.Event = function() {
2089 var loadComplete = false;
2091 var unloadListeners = [];
2093 var onAvailStack = [];
2095 var lastError = null;
2108 startInterval: function() {
2109 if (!this._interval) {
2111 var callback = function() {
2112 self._tryPreloadAttach();
2114 this._interval = setInterval(callback, this.POLL_INTERVAL);
2119 onAvailable: function(p_id, p_fn, p_obj, p_override) {
2120 onAvailStack.push({ id: p_id,
2123 override: p_override,
2124 checkReady: false });
2126 retryCount = this.POLL_RETRYS;
2127 this.startInterval();
2131 addListener: function(el, eventName, fn) {
2132 el = Roo.getDom(el);
2137 if ("unload" == eventName) {
2138 unloadListeners[unloadListeners.length] =
2139 [el, eventName, fn];
2143 var wrappedFn = function(e) {
2144 return fn(Roo.lib.Event.getEvent(e));
2147 var li = [el, eventName, fn, wrappedFn];
2149 var index = listeners.length;
2150 listeners[index] = li;
2152 this.doAdd(el, eventName, wrappedFn, false);
2158 removeListener: function(el, eventName, fn) {
2161 el = Roo.getDom(el);
2164 return this.purgeElement(el, false, eventName);
2168 if ("unload" == eventName) {
2170 for (i = 0,len = unloadListeners.length; i < len; i++) {
2171 var li = unloadListeners[i];
2174 li[1] == eventName &&
2176 unloadListeners.splice(i, 1);
2184 var cacheItem = null;
2187 var index = arguments[3];
2189 if ("undefined" == typeof index) {
2190 index = this._getCacheIndex(el, eventName, fn);
2194 cacheItem = listeners[index];
2197 if (!el || !cacheItem) {
2201 this.doRemove(el, eventName, cacheItem[this.WFN], false);
2203 delete listeners[index][this.WFN];
2204 delete listeners[index][this.FN];
2205 listeners.splice(index, 1);
2212 getTarget: function(ev, resolveTextNode) {
2213 ev = ev.browserEvent || ev;
2214 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2215 var t = ev.target || ev.srcElement;
2216 return this.resolveTextNode(t);
2220 resolveTextNode: function(node) {
2221 if (Roo.isSafari && node && 3 == node.nodeType) {
2222 return node.parentNode;
2229 getPageX: function(ev) {
2230 ev = ev.browserEvent || ev;
2231 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2233 if (!x && 0 !== x) {
2234 x = ev.clientX || 0;
2237 x += this.getScroll()[1];
2245 getPageY: function(ev) {
2246 ev = ev.browserEvent || ev;
2247 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2249 if (!y && 0 !== y) {
2250 y = ev.clientY || 0;
2253 y += this.getScroll()[0];
2262 getXY: function(ev) {
2263 ev = ev.browserEvent || ev;
2264 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2265 return [this.getPageX(ev), this.getPageY(ev)];
2269 getRelatedTarget: function(ev) {
2270 ev = ev.browserEvent || ev;
2271 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2272 var t = ev.relatedTarget;
2274 if (ev.type == "mouseout") {
2276 } else if (ev.type == "mouseover") {
2281 return this.resolveTextNode(t);
2285 getTime: function(ev) {
2286 ev = ev.browserEvent || ev;
2287 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2289 var t = new Date().getTime();
2293 this.lastError = ex;
2302 stopEvent: function(ev) {
2303 this.stopPropagation(ev);
2304 this.preventDefault(ev);
2308 stopPropagation: function(ev) {
2309 ev = ev.browserEvent || ev;
2310 if (ev.stopPropagation) {
2311 ev.stopPropagation();
2313 ev.cancelBubble = true;
2318 preventDefault: function(ev) {
2319 ev = ev.browserEvent || ev;
2320 if(ev.preventDefault) {
2321 ev.preventDefault();
2323 ev.returnValue = false;
2328 getEvent: function(e) {
2329 var ev = e || window.event;
2331 var c = this.getEvent.caller;
2333 ev = c.arguments[0];
2334 if (ev && Event == ev.constructor) {
2344 getCharCode: function(ev) {
2345 ev = ev.browserEvent || ev;
2346 return ev.charCode || ev.keyCode || 0;
2350 _getCacheIndex: function(el, eventName, fn) {
2351 for (var i = 0,len = listeners.length; i < len; ++i) {
2352 var li = listeners[i];
2354 li[this.FN] == fn &&
2355 li[this.EL] == el &&
2356 li[this.TYPE] == eventName) {
2368 getEl: function(id) {
2369 return document.getElementById(id);
2373 clearCache: function() {
2377 _load: function(e) {
2378 loadComplete = true;
2379 var EU = Roo.lib.Event;
2383 EU.doRemove(window, "load", EU._load);
2388 _tryPreloadAttach: function() {
2397 var tryAgain = !loadComplete;
2399 tryAgain = (retryCount > 0);
2404 for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2405 var item = onAvailStack[i];
2407 var el = this.getEl(item.id);
2410 if (!item.checkReady ||
2413 (document && document.body)) {
2416 if (item.override) {
2417 if (item.override === true) {
2420 scope = item.override;
2423 item.fn.call(scope, item.obj);
2424 onAvailStack[i] = null;
2427 notAvail.push(item);
2432 retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2436 this.startInterval();
2438 clearInterval(this._interval);
2439 this._interval = null;
2442 this.locked = false;
2449 purgeElement: function(el, recurse, eventName) {
2450 var elListeners = this.getListeners(el, eventName);
2452 for (var i = 0,len = elListeners.length; i < len; ++i) {
2453 var l = elListeners[i];
2454 this.removeListener(el, l.type, l.fn);
2458 if (recurse && el && el.childNodes) {
2459 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2460 this.purgeElement(el.childNodes[i], recurse, eventName);
2466 getListeners: function(el, eventName) {
2467 var results = [], searchLists;
2469 searchLists = [listeners, unloadListeners];
2470 } else if (eventName == "unload") {
2471 searchLists = [unloadListeners];
2473 searchLists = [listeners];
2476 for (var j = 0; j < searchLists.length; ++j) {
2477 var searchList = searchLists[j];
2478 if (searchList && searchList.length > 0) {
2479 for (var i = 0,len = searchList.length; i < len; ++i) {
2480 var l = searchList[i];
2481 if (l && l[this.EL] === el &&
2482 (!eventName || eventName === l[this.TYPE])) {
2487 adjust: l[this.ADJ_SCOPE],
2495 return (results.length) ? results : null;
2499 _unload: function(e) {
2501 var EU = Roo.lib.Event, i, j, l, len, index;
2503 for (i = 0,len = unloadListeners.length; i < len; ++i) {
2504 l = unloadListeners[i];
2507 if (l[EU.ADJ_SCOPE]) {
2508 if (l[EU.ADJ_SCOPE] === true) {
2511 scope = l[EU.ADJ_SCOPE];
2514 l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2515 unloadListeners[i] = null;
2521 unloadListeners = null;
2523 if (listeners && listeners.length > 0) {
2524 j = listeners.length;
2527 l = listeners[index];
2529 EU.removeListener(l[EU.EL], l[EU.TYPE],
2539 EU.doRemove(window, "unload", EU._unload);
2544 getScroll: function() {
2545 var dd = document.documentElement, db = document.body;
2546 if (dd && (dd.scrollTop || dd.scrollLeft)) {
2547 return [dd.scrollTop, dd.scrollLeft];
2549 return [db.scrollTop, db.scrollLeft];
2556 doAdd: function () {
2557 if (window.addEventListener) {
2558 return function(el, eventName, fn, capture) {
2559 el.addEventListener(eventName, fn, (capture));
2561 } else if (window.attachEvent) {
2562 return function(el, eventName, fn, capture) {
2563 el.attachEvent("on" + eventName, fn);
2572 doRemove: function() {
2573 if (window.removeEventListener) {
2574 return function (el, eventName, fn, capture) {
2575 el.removeEventListener(eventName, fn, (capture));
2577 } else if (window.detachEvent) {
2578 return function (el, eventName, fn) {
2579 el.detachEvent("on" + eventName, fn);
2591 var E = Roo.lib.Event;
2592 E.on = E.addListener;
2593 E.un = E.removeListener;
2595 if (document && document.body) {
2598 E.doAdd(window, "load", E._load);
2600 E.doAdd(window, "unload", E._unload);
2601 E._tryPreloadAttach();
2605 * Portions of this file are based on pieces of Yahoo User Interface Library
2606 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2607 * YUI licensed under the BSD License:
2608 * http://developer.yahoo.net/yui/license.txt
2609 * <script type="text/javascript">
2615 * @class Roo.lib.Ajax
2622 request : function(method, uri, cb, data, options) {
2624 var hs = options.headers;
2627 if(hs.hasOwnProperty(h)){
2628 this.initHeader(h, hs[h], false);
2632 if(options.xmlData){
2633 this.initHeader('Content-Type', 'text/xml', false);
2635 data = options.xmlData;
2639 return this.asyncRequest(method, uri, cb, data);
2642 serializeForm : function(form) {
2643 if(typeof form == 'string') {
2644 form = (document.getElementById(form) || document.forms[form]);
2647 var el, name, val, disabled, data = '', hasSubmit = false;
2648 for (var i = 0; i < form.elements.length; i++) {
2649 el = form.elements[i];
2650 disabled = form.elements[i].disabled;
2651 name = form.elements[i].name;
2652 val = form.elements[i].value;
2654 if (!disabled && name){
2658 case 'select-multiple':
2659 for (var j = 0; j < el.options.length; j++) {
2660 if (el.options[j].selected) {
2662 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2665 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2673 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2686 if(hasSubmit == false) {
2687 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2692 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2697 data = data.substr(0, data.length - 1);
2705 useDefaultHeader:true,
2707 defaultPostHeader:'application/x-www-form-urlencoded',
2709 useDefaultXhrHeader:true,
2711 defaultXhrHeader:'XMLHttpRequest',
2713 hasDefaultHeaders:true,
2725 setProgId:function(id)
2727 this.activeX.unshift(id);
2730 setDefaultPostHeader:function(b)
2732 this.useDefaultHeader = b;
2735 setDefaultXhrHeader:function(b)
2737 this.useDefaultXhrHeader = b;
2740 setPollingInterval:function(i)
2742 if (typeof i == 'number' && isFinite(i)) {
2743 this.pollInterval = i;
2747 createXhrObject:function(transactionId)
2753 http = new XMLHttpRequest();
2755 obj = { conn:http, tId:transactionId };
2759 for (var i = 0; i < this.activeX.length; ++i) {
2763 http = new ActiveXObject(this.activeX[i]);
2765 obj = { conn:http, tId:transactionId };
2778 getConnectionObject:function()
2781 var tId = this.transactionId;
2785 o = this.createXhrObject(tId);
2787 this.transactionId++;
2798 asyncRequest:function(method, uri, callback, postData)
2800 var o = this.getConnectionObject();
2806 o.conn.open(method, uri, true);
2808 if (this.useDefaultXhrHeader) {
2809 if (!this.defaultHeaders['X-Requested-With']) {
2810 this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2814 if(postData && this.useDefaultHeader){
2815 this.initHeader('Content-Type', this.defaultPostHeader);
2818 if (this.hasDefaultHeaders || this.hasHeaders) {
2822 this.handleReadyState(o, callback);
2823 o.conn.send(postData || null);
2829 handleReadyState:function(o, callback)
2833 if (callback && callback.timeout) {
2835 this.timeout[o.tId] = window.setTimeout(function() {
2836 oConn.abort(o, callback, true);
2837 }, callback.timeout);
2840 this.poll[o.tId] = window.setInterval(
2842 if (o.conn && o.conn.readyState == 4) {
2843 window.clearInterval(oConn.poll[o.tId]);
2844 delete oConn.poll[o.tId];
2846 if(callback && callback.timeout) {
2847 window.clearTimeout(oConn.timeout[o.tId]);
2848 delete oConn.timeout[o.tId];
2851 oConn.handleTransactionResponse(o, callback);
2854 , this.pollInterval);
2857 handleTransactionResponse:function(o, callback, isAbort)
2861 this.releaseObject(o);
2865 var httpStatus, responseObject;
2869 if (o.conn.status !== undefined && o.conn.status != 0) {
2870 httpStatus = o.conn.status;
2882 if (httpStatus >= 200 && httpStatus < 300) {
2883 responseObject = this.createResponseObject(o, callback.argument);
2884 if (callback.success) {
2885 if (!callback.scope) {
2886 callback.success(responseObject);
2891 callback.success.apply(callback.scope, [responseObject]);
2896 switch (httpStatus) {
2904 responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2905 if (callback.failure) {
2906 if (!callback.scope) {
2907 callback.failure(responseObject);
2910 callback.failure.apply(callback.scope, [responseObject]);
2915 responseObject = this.createResponseObject(o, callback.argument);
2916 if (callback.failure) {
2917 if (!callback.scope) {
2918 callback.failure(responseObject);
2921 callback.failure.apply(callback.scope, [responseObject]);
2927 this.releaseObject(o);
2928 responseObject = null;
2931 createResponseObject:function(o, callbackArg)
2938 var headerStr = o.conn.getAllResponseHeaders();
2939 var header = headerStr.split('\n');
2940 for (var i = 0; i < header.length; i++) {
2941 var delimitPos = header[i].indexOf(':');
2942 if (delimitPos != -1) {
2943 headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2951 obj.status = o.conn.status;
2952 obj.statusText = o.conn.statusText;
2953 obj.getResponseHeader = headerObj;
2954 obj.getAllResponseHeaders = headerStr;
2955 obj.responseText = o.conn.responseText;
2956 obj.responseXML = o.conn.responseXML;
2958 if (typeof callbackArg !== undefined) {
2959 obj.argument = callbackArg;
2965 createExceptionObject:function(tId, callbackArg, isAbort)
2968 var COMM_ERROR = 'communication failure';
2969 var ABORT_CODE = -1;
2970 var ABORT_ERROR = 'transaction aborted';
2976 obj.status = ABORT_CODE;
2977 obj.statusText = ABORT_ERROR;
2980 obj.status = COMM_CODE;
2981 obj.statusText = COMM_ERROR;
2985 obj.argument = callbackArg;
2991 initHeader:function(label, value, isDefault)
2993 var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2995 if (headerObj[label] === undefined) {
2996 headerObj[label] = value;
3001 headerObj[label] = value + "," + headerObj[label];
3005 this.hasDefaultHeaders = true;
3008 this.hasHeaders = true;
3013 setHeader:function(o)
3015 if (this.hasDefaultHeaders) {
3016 for (var prop in this.defaultHeaders) {
3017 if (this.defaultHeaders.hasOwnProperty(prop)) {
3018 o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
3023 if (this.hasHeaders) {
3024 for (var prop in this.headers) {
3025 if (this.headers.hasOwnProperty(prop)) {
3026 o.conn.setRequestHeader(prop, this.headers[prop]);
3030 this.hasHeaders = false;
3034 resetDefaultHeaders:function() {
3035 delete this.defaultHeaders;
3036 this.defaultHeaders = {};
3037 this.hasDefaultHeaders = false;
3040 abort:function(o, callback, isTimeout)
3042 if(this.isCallInProgress(o)) {
3044 window.clearInterval(this.poll[o.tId]);
3045 delete this.poll[o.tId];
3047 delete this.timeout[o.tId];
3050 this.handleTransactionResponse(o, callback, true);
3060 isCallInProgress:function(o)
3063 return o.conn.readyState != 4 && o.conn.readyState != 0;
3072 releaseObject:function(o)
3081 'MSXML2.XMLHTTP.3.0',
3089 * Portions of this file are based on pieces of Yahoo User Interface Library
3090 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3091 * YUI licensed under the BSD License:
3092 * http://developer.yahoo.net/yui/license.txt
3093 * <script type="text/javascript">
3097 Roo.lib.Region = function(t, r, b, l) {
3107 Roo.lib.Region.prototype = {
3108 contains : function(region) {
3109 return ( region.left >= this.left &&
3110 region.right <= this.right &&
3111 region.top >= this.top &&
3112 region.bottom <= this.bottom );
3116 getArea : function() {
3117 return ( (this.bottom - this.top) * (this.right - this.left) );
3120 intersect : function(region) {
3121 var t = Math.max(this.top, region.top);
3122 var r = Math.min(this.right, region.right);
3123 var b = Math.min(this.bottom, region.bottom);
3124 var l = Math.max(this.left, region.left);
3126 if (b >= t && r >= l) {
3127 return new Roo.lib.Region(t, r, b, l);
3132 union : function(region) {
3133 var t = Math.min(this.top, region.top);
3134 var r = Math.max(this.right, region.right);
3135 var b = Math.max(this.bottom, region.bottom);
3136 var l = Math.min(this.left, region.left);
3138 return new Roo.lib.Region(t, r, b, l);
3141 adjust : function(t, l, b, r) {
3150 Roo.lib.Region.getRegion = function(el) {
3151 var p = Roo.lib.Dom.getXY(el);
3154 var r = p[0] + el.offsetWidth;
3155 var b = p[1] + el.offsetHeight;
3158 return new Roo.lib.Region(t, r, b, l);
3161 * Portions of this file are based on pieces of Yahoo User Interface Library
3162 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3163 * YUI licensed under the BSD License:
3164 * http://developer.yahoo.net/yui/license.txt
3165 * <script type="text/javascript">
3168 //@@dep Roo.lib.Region
3171 Roo.lib.Point = function(x, y) {
3172 if (x instanceof Array) {
3176 this.x = this.right = this.left = this[0] = x;
3177 this.y = this.top = this.bottom = this[1] = y;
3180 Roo.lib.Point.prototype = new Roo.lib.Region();
3182 * Portions of this file are based on pieces of Yahoo User Interface Library
3183 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3184 * YUI licensed under the BSD License:
3185 * http://developer.yahoo.net/yui/license.txt
3186 * <script type="text/javascript">
3193 scroll : function(el, args, duration, easing, cb, scope) {
3194 this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3197 motion : function(el, args, duration, easing, cb, scope) {
3198 this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3201 color : function(el, args, duration, easing, cb, scope) {
3202 this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3205 run : function(el, args, duration, easing, cb, scope, type) {
3206 type = type || Roo.lib.AnimBase;
3207 if (typeof easing == "string") {
3208 easing = Roo.lib.Easing[easing];
3210 var anim = new type(el, args, duration, easing);
3211 anim.animateX(function() {
3212 Roo.callback(cb, scope);
3218 * Portions of this file are based on pieces of Yahoo User Interface Library
3219 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3220 * YUI licensed under the BSD License:
3221 * http://developer.yahoo.net/yui/license.txt
3222 * <script type="text/javascript">
3230 if (!libFlyweight) {
3231 libFlyweight = new Roo.Element.Flyweight();
3233 libFlyweight.dom = el;
3234 return libFlyweight;
3237 // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3241 Roo.lib.AnimBase = function(el, attributes, duration, method) {
3243 this.init(el, attributes, duration, method);
3247 Roo.lib.AnimBase.fly = fly;
3251 Roo.lib.AnimBase.prototype = {
3253 toString: function() {
3254 var el = this.getEl();
3255 var id = el.id || el.tagName;
3256 return ("Anim " + id);
3260 noNegatives: /width|height|opacity|padding/i,
3261 offsetAttribute: /^((width|height)|(top|left))$/,
3262 defaultUnit: /width|height|top$|bottom$|left$|right$/i,
3263 offsetUnit: /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3267 doMethod: function(attr, start, end) {
3268 return this.method(this.currentFrame, start, end - start, this.totalFrames);
3272 setAttribute: function(attr, val, unit) {
3273 if (this.patterns.noNegatives.test(attr)) {
3274 val = (val > 0) ? val : 0;
3277 Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3281 getAttribute: function(attr) {
3282 var el = this.getEl();
3283 var val = fly(el).getStyle(attr);
3285 if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3286 return parseFloat(val);
3289 var a = this.patterns.offsetAttribute.exec(attr) || [];
3290 var pos = !!( a[3] );
3291 var box = !!( a[2] );
3294 if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3295 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3304 getDefaultUnit: function(attr) {
3305 if (this.patterns.defaultUnit.test(attr)) {
3312 animateX : function(callback, scope) {
3313 var f = function() {
3314 this.onComplete.removeListener(f);
3315 if (typeof callback == "function") {
3316 callback.call(scope || this, this);
3319 this.onComplete.addListener(f, this);
3324 setRuntimeAttribute: function(attr) {
3327 var attributes = this.attributes;
3329 this.runtimeAttributes[attr] = {};
3331 var isset = function(prop) {
3332 return (typeof prop !== 'undefined');
3335 if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3339 start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3342 if (isset(attributes[attr]['to'])) {
3343 end = attributes[attr]['to'];
3344 } else if (isset(attributes[attr]['by'])) {
3345 if (start.constructor == Array) {
3347 for (var i = 0, len = start.length; i < len; ++i) {
3348 end[i] = start[i] + attributes[attr]['by'][i];
3351 end = start + attributes[attr]['by'];
3355 this.runtimeAttributes[attr].start = start;
3356 this.runtimeAttributes[attr].end = end;
3359 this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3363 init: function(el, attributes, duration, method) {
3365 var isAnimated = false;
3368 var startTime = null;
3371 var actualFrames = 0;
3374 el = Roo.getDom(el);
3377 this.attributes = attributes || {};
3380 this.duration = duration || 1;
3383 this.method = method || Roo.lib.Easing.easeNone;
3386 this.useSeconds = true;
3389 this.currentFrame = 0;
3392 this.totalFrames = Roo.lib.AnimMgr.fps;
3395 this.getEl = function() {
3400 this.isAnimated = function() {
3405 this.getStartTime = function() {
3409 this.runtimeAttributes = {};
3412 this.animate = function() {
3413 if (this.isAnimated()) {
3417 this.currentFrame = 0;
3419 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3421 Roo.lib.AnimMgr.registerElement(this);
3425 this.stop = function(finish) {
3427 this.currentFrame = this.totalFrames;
3428 this._onTween.fire();
3430 Roo.lib.AnimMgr.stop(this);
3433 var onStart = function() {
3434 this.onStart.fire();
3436 this.runtimeAttributes = {};
3437 for (var attr in this.attributes) {
3438 this.setRuntimeAttribute(attr);
3443 startTime = new Date();
3447 var onTween = function() {
3449 duration: new Date() - this.getStartTime(),
3450 currentFrame: this.currentFrame
3453 data.toString = function() {
3455 'duration: ' + data.duration +
3456 ', currentFrame: ' + data.currentFrame
3460 this.onTween.fire(data);
3462 var runtimeAttributes = this.runtimeAttributes;
3464 for (var attr in runtimeAttributes) {
3465 this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3471 var onComplete = function() {
3472 var actual_duration = (new Date() - startTime) / 1000 ;
3475 duration: actual_duration,
3476 frames: actualFrames,
3477 fps: actualFrames / actual_duration
3480 data.toString = function() {
3482 'duration: ' + data.duration +
3483 ', frames: ' + data.frames +
3484 ', fps: ' + data.fps
3490 this.onComplete.fire(data);
3494 this._onStart = new Roo.util.Event(this);
3495 this.onStart = new Roo.util.Event(this);
3496 this.onTween = new Roo.util.Event(this);
3497 this._onTween = new Roo.util.Event(this);
3498 this.onComplete = new Roo.util.Event(this);
3499 this._onComplete = new Roo.util.Event(this);
3500 this._onStart.addListener(onStart);
3501 this._onTween.addListener(onTween);
3502 this._onComplete.addListener(onComplete);
3507 * Portions of this file are based on pieces of Yahoo User Interface Library
3508 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3509 * YUI licensed under the BSD License:
3510 * http://developer.yahoo.net/yui/license.txt
3511 * <script type="text/javascript">
3515 Roo.lib.AnimMgr = new function() {
3532 this.registerElement = function(tween) {
3533 queue[queue.length] = tween;
3535 tween._onStart.fire();
3540 this.unRegister = function(tween, index) {
3541 tween._onComplete.fire();
3542 index = index || getIndex(tween);
3544 queue.splice(index, 1);
3548 if (tweenCount <= 0) {
3554 this.start = function() {
3555 if (thread === null) {
3556 thread = setInterval(this.run, this.delay);
3561 this.stop = function(tween) {
3563 clearInterval(thread);
3565 for (var i = 0, len = queue.length; i < len; ++i) {
3566 if (queue[0].isAnimated()) {
3567 this.unRegister(queue[0], 0);
3576 this.unRegister(tween);
3581 this.run = function() {
3582 for (var i = 0, len = queue.length; i < len; ++i) {
3583 var tween = queue[i];
3584 if (!tween || !tween.isAnimated()) {
3588 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3590 tween.currentFrame += 1;
3592 if (tween.useSeconds) {
3593 correctFrame(tween);
3595 tween._onTween.fire();
3598 Roo.lib.AnimMgr.stop(tween, i);
3603 var getIndex = function(anim) {
3604 for (var i = 0, len = queue.length; i < len; ++i) {
3605 if (queue[i] == anim) {
3613 var correctFrame = function(tween) {
3614 var frames = tween.totalFrames;
3615 var frame = tween.currentFrame;
3616 var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3617 var elapsed = (new Date() - tween.getStartTime());
3620 if (elapsed < tween.duration * 1000) {
3621 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3623 tweak = frames - (frame + 1);
3625 if (tweak > 0 && isFinite(tweak)) {
3626 if (tween.currentFrame + tweak >= frames) {
3627 tweak = frames - (frame + 1);
3630 tween.currentFrame += tweak;
3636 * Portions of this file are based on pieces of Yahoo User Interface Library
3637 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3638 * YUI licensed under the BSD License:
3639 * http://developer.yahoo.net/yui/license.txt
3640 * <script type="text/javascript">
3643 Roo.lib.Bezier = new function() {
3645 this.getPosition = function(points, t) {
3646 var n = points.length;
3649 for (var i = 0; i < n; ++i) {
3650 tmp[i] = [points[i][0], points[i][1]];
3653 for (var j = 1; j < n; ++j) {
3654 for (i = 0; i < n - j; ++i) {
3655 tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3656 tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3660 return [ tmp[0][0], tmp[0][1] ];
3664 * Portions of this file are based on pieces of Yahoo User Interface Library
3665 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3666 * YUI licensed under the BSD License:
3667 * http://developer.yahoo.net/yui/license.txt
3668 * <script type="text/javascript">
3673 Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3674 Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3677 Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3679 var fly = Roo.lib.AnimBase.fly;
3681 var superclass = Y.ColorAnim.superclass;
3682 var proto = Y.ColorAnim.prototype;
3684 proto.toString = function() {
3685 var el = this.getEl();
3686 var id = el.id || el.tagName;
3687 return ("ColorAnim " + id);
3690 proto.patterns.color = /color$/i;
3691 proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3692 proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3693 proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3694 proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3697 proto.parseColor = function(s) {
3698 if (s.length == 3) {
3702 var c = this.patterns.hex.exec(s);
3703 if (c && c.length == 4) {
3704 return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3707 c = this.patterns.rgb.exec(s);
3708 if (c && c.length == 4) {
3709 return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3712 c = this.patterns.hex3.exec(s);
3713 if (c && c.length == 4) {
3714 return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3719 // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3720 proto.getAttribute = function(attr) {
3721 var el = this.getEl();
3722 if (this.patterns.color.test(attr)) {
3723 var val = fly(el).getStyle(attr);
3725 if (this.patterns.transparent.test(val)) {
3726 var parent = el.parentNode;
3727 val = fly(parent).getStyle(attr);
3729 while (parent && this.patterns.transparent.test(val)) {
3730 parent = parent.parentNode;
3731 val = fly(parent).getStyle(attr);
3732 if (parent.tagName.toUpperCase() == 'HTML') {
3738 val = superclass.getAttribute.call(this, attr);
3743 proto.getAttribute = function(attr) {
3744 var el = this.getEl();
3745 if (this.patterns.color.test(attr)) {
3746 var val = fly(el).getStyle(attr);
3748 if (this.patterns.transparent.test(val)) {
3749 var parent = el.parentNode;
3750 val = fly(parent).getStyle(attr);
3752 while (parent && this.patterns.transparent.test(val)) {
3753 parent = parent.parentNode;
3754 val = fly(parent).getStyle(attr);
3755 if (parent.tagName.toUpperCase() == 'HTML') {
3761 val = superclass.getAttribute.call(this, attr);
3767 proto.doMethod = function(attr, start, end) {
3770 if (this.patterns.color.test(attr)) {
3772 for (var i = 0, len = start.length; i < len; ++i) {
3773 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3776 val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3779 val = superclass.doMethod.call(this, attr, start, end);
3785 proto.setRuntimeAttribute = function(attr) {
3786 superclass.setRuntimeAttribute.call(this, attr);
3788 if (this.patterns.color.test(attr)) {
3789 var attributes = this.attributes;
3790 var start = this.parseColor(this.runtimeAttributes[attr].start);
3791 var end = this.parseColor(this.runtimeAttributes[attr].end);
3793 if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3794 end = this.parseColor(attributes[attr].by);
3796 for (var i = 0, len = start.length; i < len; ++i) {
3797 end[i] = start[i] + end[i];
3801 this.runtimeAttributes[attr].start = start;
3802 this.runtimeAttributes[attr].end = end;
3808 * Portions of this file are based on pieces of Yahoo User Interface Library
3809 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3810 * YUI licensed under the BSD License:
3811 * http://developer.yahoo.net/yui/license.txt
3812 * <script type="text/javascript">
3818 easeNone: function (t, b, c, d) {
3819 return c * t / d + b;
3823 easeIn: function (t, b, c, d) {
3824 return c * (t /= d) * t + b;
3828 easeOut: function (t, b, c, d) {
3829 return -c * (t /= d) * (t - 2) + b;
3833 easeBoth: function (t, b, c, d) {
3834 if ((t /= d / 2) < 1) {
3835 return c / 2 * t * t + b;
3838 return -c / 2 * ((--t) * (t - 2) - 1) + b;
3842 easeInStrong: function (t, b, c, d) {
3843 return c * (t /= d) * t * t * t + b;
3847 easeOutStrong: function (t, b, c, d) {
3848 return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3852 easeBothStrong: function (t, b, c, d) {
3853 if ((t /= d / 2) < 1) {
3854 return c / 2 * t * t * t * t + b;
3857 return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3862 elasticIn: function (t, b, c, d, a, p) {
3866 if ((t /= d) == 1) {
3873 if (!a || a < Math.abs(c)) {
3878 var s = p / (2 * Math.PI) * Math.asin(c / a);
3881 return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3885 elasticOut: function (t, b, c, d, a, p) {
3889 if ((t /= d) == 1) {
3896 if (!a || a < Math.abs(c)) {
3901 var s = p / (2 * Math.PI) * Math.asin(c / a);
3904 return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3908 elasticBoth: function (t, b, c, d, a, p) {
3913 if ((t /= d / 2) == 2) {
3921 if (!a || a < Math.abs(c)) {
3926 var s = p / (2 * Math.PI) * Math.asin(c / a);
3930 return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3931 Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3933 return a * Math.pow(2, -10 * (t -= 1)) *
3934 Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3939 backIn: function (t, b, c, d, s) {
3940 if (typeof s == 'undefined') {
3943 return c * (t /= d) * t * ((s + 1) * t - s) + b;
3947 backOut: function (t, b, c, d, s) {
3948 if (typeof s == 'undefined') {
3951 return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3955 backBoth: function (t, b, c, d, s) {
3956 if (typeof s == 'undefined') {
3960 if ((t /= d / 2 ) < 1) {
3961 return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3963 return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3967 bounceIn: function (t, b, c, d) {
3968 return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3972 bounceOut: function (t, b, c, d) {
3973 if ((t /= d) < (1 / 2.75)) {
3974 return c * (7.5625 * t * t) + b;
3975 } else if (t < (2 / 2.75)) {
3976 return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3977 } else if (t < (2.5 / 2.75)) {
3978 return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3980 return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3984 bounceBoth: function (t, b, c, d) {
3986 return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3988 return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3991 * Portions of this file are based on pieces of Yahoo User Interface Library
3992 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3993 * YUI licensed under the BSD License:
3994 * http://developer.yahoo.net/yui/license.txt
3995 * <script type="text/javascript">
3999 Roo.lib.Motion = function(el, attributes, duration, method) {
4001 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
4005 Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
4009 var superclass = Y.Motion.superclass;
4010 var proto = Y.Motion.prototype;
4012 proto.toString = function() {
4013 var el = this.getEl();
4014 var id = el.id || el.tagName;
4015 return ("Motion " + id);
4018 proto.patterns.points = /^points$/i;
4020 proto.setAttribute = function(attr, val, unit) {
4021 if (this.patterns.points.test(attr)) {
4022 unit = unit || 'px';
4023 superclass.setAttribute.call(this, 'left', val[0], unit);
4024 superclass.setAttribute.call(this, 'top', val[1], unit);
4026 superclass.setAttribute.call(this, attr, val, unit);
4030 proto.getAttribute = function(attr) {
4031 if (this.patterns.points.test(attr)) {
4033 superclass.getAttribute.call(this, 'left'),
4034 superclass.getAttribute.call(this, 'top')
4037 val = superclass.getAttribute.call(this, attr);
4043 proto.doMethod = function(attr, start, end) {
4046 if (this.patterns.points.test(attr)) {
4047 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
4048 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
4050 val = superclass.doMethod.call(this, attr, start, end);
4055 proto.setRuntimeAttribute = function(attr) {
4056 if (this.patterns.points.test(attr)) {
4057 var el = this.getEl();
4058 var attributes = this.attributes;
4060 var control = attributes['points']['control'] || [];
4064 if (control.length > 0 && !(control[0] instanceof Array)) {
4065 control = [control];
4068 for (i = 0,len = control.length; i < len; ++i) {
4069 tmp[i] = control[i];
4074 Roo.fly(el).position();
4076 if (isset(attributes['points']['from'])) {
4077 Roo.lib.Dom.setXY(el, attributes['points']['from']);
4080 Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
4083 start = this.getAttribute('points');
4086 if (isset(attributes['points']['to'])) {
4087 end = translateValues.call(this, attributes['points']['to'], start);
4089 var pageXY = Roo.lib.Dom.getXY(this.getEl());
4090 for (i = 0,len = control.length; i < len; ++i) {
4091 control[i] = translateValues.call(this, control[i], start);
4095 } else if (isset(attributes['points']['by'])) {
4096 end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
4098 for (i = 0,len = control.length; i < len; ++i) {
4099 control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
4103 this.runtimeAttributes[attr] = [start];
4105 if (control.length > 0) {
4106 this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
4109 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
4112 superclass.setRuntimeAttribute.call(this, attr);
4116 var translateValues = function(val, start) {
4117 var pageXY = Roo.lib.Dom.getXY(this.getEl());
4118 val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4123 var isset = function(prop) {
4124 return (typeof prop !== 'undefined');
4128 * Portions of this file are based on pieces of Yahoo User Interface Library
4129 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4130 * YUI licensed under the BSD License:
4131 * http://developer.yahoo.net/yui/license.txt
4132 * <script type="text/javascript">
4136 Roo.lib.Scroll = function(el, attributes, duration, method) {
4138 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4142 Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4146 var superclass = Y.Scroll.superclass;
4147 var proto = Y.Scroll.prototype;
4149 proto.toString = function() {
4150 var el = this.getEl();
4151 var id = el.id || el.tagName;
4152 return ("Scroll " + id);
4155 proto.doMethod = function(attr, start, end) {
4158 if (attr == 'scroll') {
4160 this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4161 this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4165 val = superclass.doMethod.call(this, attr, start, end);
4170 proto.getAttribute = function(attr) {
4172 var el = this.getEl();
4174 if (attr == 'scroll') {
4175 val = [ el.scrollLeft, el.scrollTop ];
4177 val = superclass.getAttribute.call(this, attr);
4183 proto.setAttribute = function(attr, val, unit) {
4184 var el = this.getEl();
4186 if (attr == 'scroll') {
4187 el.scrollLeft = val[0];
4188 el.scrollTop = val[1];
4190 superclass.setAttribute.call(this, attr, val, unit);
4196 * Ext JS Library 1.1.1
4197 * Copyright(c) 2006-2007, Ext JS, LLC.
4199 * Originally Released Under LGPL - original licence link has changed is not relivant.
4202 * <script type="text/javascript">
4206 // nasty IE9 hack - what a pile of crap that is..
4208 if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4209 Range.prototype.createContextualFragment = function (html) {
4210 var doc = window.document;
4211 var container = doc.createElement("div");
4212 container.innerHTML = html;
4213 var frag = doc.createDocumentFragment(), n;
4214 while ((n = container.firstChild)) {
4215 frag.appendChild(n);
4222 * @class Roo.DomHelper
4223 * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4224 * 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>.
4227 Roo.DomHelper = function(){
4228 var tempTableEl = null;
4229 var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4230 var tableRe = /^table|tbody|tr|td$/i;
4232 // build as innerHTML where available
4234 var createHtml = function(o){
4235 if(typeof o == 'string'){
4244 if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") { continue; }
4245 if(attr == "style"){
4247 if(typeof s == "function"){
4250 if(typeof s == "string"){
4251 b += ' style="' + s + '"';
4252 }else if(typeof s == "object"){
4255 if(typeof s[key] != "function"){
4256 b += key + ":" + s[key] + ";";
4263 b += ' class="' + o["cls"] + '"';
4264 }else if(attr == "htmlFor"){
4265 b += ' for="' + o["htmlFor"] + '"';
4267 b += " " + attr + '="' + o[attr] + '"';
4271 if(emptyTags.test(o.tag)){
4275 var cn = o.children || o.cn;
4277 //http://bugs.kde.org/show_bug.cgi?id=71506
4278 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4279 for(var i = 0, len = cn.length; i < len; i++) {
4280 b += createHtml(cn[i], b);
4283 b += createHtml(cn, b);
4289 b += "</" + o.tag + ">";
4296 var createDom = function(o, parentNode){
4298 // defininition craeted..
4300 if (o.ns && o.ns != 'html') {
4302 if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4303 xmlns[o.ns] = o.xmlns;
4306 if (typeof(xmlns[o.ns]) == 'undefined') {
4307 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4313 if (typeof(o) == 'string') {
4314 return parentNode.appendChild(document.createTextNode(o));
4316 o.tag = o.tag || div;
4317 if (o.ns && Roo.isIE) {
4319 o.tag = o.ns + ':' + o.tag;
4322 var el = ns ? document.createElementNS( ns, o.tag||'div') : document.createElement(o.tag||'div');
4323 var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4326 if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" ||
4327 attr == "style" || typeof o[attr] == "function") { continue; }
4329 if(attr=="cls" && Roo.isIE){
4330 el.className = o["cls"];
4332 if(useSet) { el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);}
4338 Roo.DomHelper.applyStyles(el, o.style);
4339 var cn = o.children || o.cn;
4341 //http://bugs.kde.org/show_bug.cgi?id=71506
4342 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4343 for(var i = 0, len = cn.length; i < len; i++) {
4344 createDom(cn[i], el);
4351 el.innerHTML = o.html;
4354 parentNode.appendChild(el);
4359 var ieTable = function(depth, s, h, e){
4360 tempTableEl.innerHTML = [s, h, e].join('');
4361 var i = -1, el = tempTableEl;
4368 // kill repeat to save bytes
4372 tbe = '</tbody>'+te,
4378 * Nasty code for IE's broken table implementation
4380 var insertIntoTable = function(tag, where, el, html){
4382 tempTableEl = document.createElement('div');
4387 if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4390 if(where == 'beforebegin'){
4394 before = el.nextSibling;
4397 node = ieTable(4, trs, html, tre);
4399 else if(tag == 'tr'){
4400 if(where == 'beforebegin'){
4403 node = ieTable(3, tbs, html, tbe);
4404 } else if(where == 'afterend'){
4405 before = el.nextSibling;
4407 node = ieTable(3, tbs, html, tbe);
4408 } else{ // INTO a TR
4409 if(where == 'afterbegin'){
4410 before = el.firstChild;
4412 node = ieTable(4, trs, html, tre);
4414 } else if(tag == 'tbody'){
4415 if(where == 'beforebegin'){
4418 node = ieTable(2, ts, html, te);
4419 } else if(where == 'afterend'){
4420 before = el.nextSibling;
4422 node = ieTable(2, ts, html, te);
4424 if(where == 'afterbegin'){
4425 before = el.firstChild;
4427 node = ieTable(3, tbs, html, tbe);
4430 if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4433 if(where == 'afterbegin'){
4434 before = el.firstChild;
4436 node = ieTable(2, ts, html, te);
4438 el.insertBefore(node, before);
4443 /** True to force the use of DOM instead of html fragments @type Boolean */
4447 * Returns the markup for the passed Element(s) config
4448 * @param {Object} o The Dom object spec (and children)
4451 markup : function(o){
4452 return createHtml(o);
4456 * Applies a style specification to an element
4457 * @param {String/HTMLElement} el The element to apply styles to
4458 * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4459 * a function which returns such a specification.
4461 applyStyles : function(el, styles){
4464 if(typeof styles == "string"){
4465 var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4467 while ((matches = re.exec(styles)) != null){
4468 el.setStyle(matches[1], matches[2]);
4470 }else if (typeof styles == "object"){
4471 for (var style in styles){
4472 el.setStyle(style, styles[style]);
4474 }else if (typeof styles == "function"){
4475 Roo.DomHelper.applyStyles(el, styles.call());
4481 * Inserts an HTML fragment into the Dom
4482 * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4483 * @param {HTMLElement} el The context element
4484 * @param {String} html The HTML fragmenet
4485 * @return {HTMLElement} The new node
4487 insertHtml : function(where, el, html){
4488 where = where.toLowerCase();
4489 if(el.insertAdjacentHTML){
4490 if(tableRe.test(el.tagName)){
4492 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4498 el.insertAdjacentHTML('BeforeBegin', html);
4499 return el.previousSibling;
4501 el.insertAdjacentHTML('AfterBegin', html);
4502 return el.firstChild;
4504 el.insertAdjacentHTML('BeforeEnd', html);
4505 return el.lastChild;
4507 el.insertAdjacentHTML('AfterEnd', html);
4508 return el.nextSibling;
4510 throw 'Illegal insertion point -> "' + where + '"';
4512 var range = el.ownerDocument.createRange();
4516 range.setStartBefore(el);
4517 frag = range.createContextualFragment(html);
4518 el.parentNode.insertBefore(frag, el);
4519 return el.previousSibling;
4522 range.setStartBefore(el.firstChild);
4523 frag = range.createContextualFragment(html);
4524 el.insertBefore(frag, el.firstChild);
4525 return el.firstChild;
4527 el.innerHTML = html;
4528 return el.firstChild;
4532 range.setStartAfter(el.lastChild);
4533 frag = range.createContextualFragment(html);
4534 el.appendChild(frag);
4535 return el.lastChild;
4537 el.innerHTML = html;
4538 return el.lastChild;
4541 range.setStartAfter(el);
4542 frag = range.createContextualFragment(html);
4543 el.parentNode.insertBefore(frag, el.nextSibling);
4544 return el.nextSibling;
4546 throw 'Illegal insertion point -> "' + where + '"';
4550 * Creates new Dom element(s) and inserts them before el
4551 * @param {String/HTMLElement/Element} el The context element
4552 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4553 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4554 * @return {HTMLElement/Roo.Element} The new node
4556 insertBefore : function(el, o, returnElement){
4557 return this.doInsert(el, o, returnElement, "beforeBegin");
4561 * Creates new Dom element(s) and inserts them after el
4562 * @param {String/HTMLElement/Element} el The context element
4563 * @param {Object} o The Dom object spec (and children)
4564 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4565 * @return {HTMLElement/Roo.Element} The new node
4567 insertAfter : function(el, o, returnElement){
4568 return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4572 * Creates new Dom element(s) and inserts them as the first child of el
4573 * @param {String/HTMLElement/Element} el The context element
4574 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4575 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4576 * @return {HTMLElement/Roo.Element} The new node
4578 insertFirst : function(el, o, returnElement){
4579 return this.doInsert(el, o, returnElement, "afterBegin");
4583 doInsert : function(el, o, returnElement, pos, sibling){
4584 el = Roo.getDom(el);
4586 if(this.useDom || o.ns){
4587 newNode = createDom(o, null);
4588 el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4590 var html = createHtml(o);
4591 newNode = this.insertHtml(pos, el, html);
4593 return returnElement ? Roo.get(newNode, true) : newNode;
4597 * Creates new Dom element(s) and appends them to el
4598 * @param {String/HTMLElement/Element} el The context element
4599 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4600 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4601 * @return {HTMLElement/Roo.Element} The new node
4603 append : function(el, o, returnElement){
4604 el = Roo.getDom(el);
4606 if(this.useDom || o.ns){
4607 newNode = createDom(o, null);
4608 el.appendChild(newNode);
4610 var html = createHtml(o);
4611 newNode = this.insertHtml("beforeEnd", el, html);
4613 return returnElement ? Roo.get(newNode, true) : newNode;
4617 * Creates new Dom element(s) and overwrites the contents of el with them
4618 * @param {String/HTMLElement/Element} el The context element
4619 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4620 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4621 * @return {HTMLElement/Roo.Element} The new node
4623 overwrite : function(el, o, returnElement){
4624 el = Roo.getDom(el);
4627 while (el.childNodes.length) {
4628 el.removeChild(el.firstChild);
4632 el.innerHTML = createHtml(o);
4635 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4639 * Creates a new Roo.DomHelper.Template from the Dom object spec
4640 * @param {Object} o The Dom object spec (and children)
4641 * @return {Roo.DomHelper.Template} The new template
4643 createTemplate : function(o){
4644 var html = createHtml(o);
4645 return new Roo.Template(html);
4651 * Ext JS Library 1.1.1
4652 * Copyright(c) 2006-2007, Ext JS, LLC.
4654 * Originally Released Under LGPL - original licence link has changed is not relivant.
4657 * <script type="text/javascript">
4661 * @class Roo.Template
4662 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4663 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4666 var t = new Roo.Template({
4667 html : '<div name="{id}">' +
4668 '<span class="{cls}">{name:trim} {someval:this.myformat}{value:ellipsis(10)}</span>' +
4670 myformat: function (value, allValues) {
4671 return 'XX' + value;
4674 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4676 * For more information see this blog post with examples:
4677 * <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4678 - Create Elements using DOM, HTML fragments and Templates</a>.
4680 * @param {Object} cfg - Configuration object.
4682 Roo.Template = function(cfg){
4684 if(cfg instanceof Array){
4686 }else if(arguments.length > 1){
4687 cfg = Array.prototype.join.call(arguments, "");
4691 if (typeof(cfg) == 'object') {
4702 Roo.Template.prototype = {
4705 * @cfg {Function} onLoad Called after the template has been loaded and complied (usually from a remove source)
4711 * @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..
4712 * it should be fixed so that template is observable...
4716 * @cfg {String} html The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4724 * Returns an HTML fragment of this template with the specified values applied.
4725 * @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'})
4726 * @return {String} The HTML fragment
4731 applyTemplate : function(values){
4732 //Roo.log(["applyTemplate", values]);
4736 return this.compiled(values);
4738 var useF = this.disableFormats !== true;
4739 var fm = Roo.util.Format, tpl = this;
4740 var fn = function(m, name, format, args){
4742 if(format.substr(0, 5) == "this."){
4743 return tpl.call(format.substr(5), values[name], values);
4746 // quoted values are required for strings in compiled templates,
4747 // but for non compiled we need to strip them
4748 // quoted reversed for jsmin
4749 var re = /^\s*['"](.*)["']\s*$/;
4750 args = args.split(',');
4751 for(var i = 0, len = args.length; i < len; i++){
4752 args[i] = args[i].replace(re, "$1");
4754 args = [values[name]].concat(args);
4756 args = [values[name]];
4758 return fm[format].apply(fm, args);
4761 return values[name] !== undefined ? values[name] : "";
4764 return this.html.replace(this.re, fn);
4782 this.loading = true;
4783 this.compiled = false;
4785 var cx = new Roo.data.Connection();
4789 success : function (response) {
4793 _t.set(response.responseText,true);
4799 failure : function(response) {
4800 Roo.log("Template failed to load from " + _t.url);
4807 * Sets the HTML used as the template and optionally compiles it.
4808 * @param {String} html
4809 * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4810 * @return {Roo.Template} this
4812 set : function(html, compile){
4814 this.compiled = false;
4822 * True to disable format functions (defaults to false)
4825 disableFormats : false,
4828 * The regular expression used to match template variables
4832 re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4835 * Compiles the template into an internal function, eliminating the RegEx overhead.
4836 * @return {Roo.Template} this
4838 compile : function(){
4839 var fm = Roo.util.Format;
4840 var useF = this.disableFormats !== true;
4841 var sep = Roo.isGecko ? "+" : ",";
4842 var fn = function(m, name, format, args){
4844 args = args ? ',' + args : "";
4845 if(format.substr(0, 5) != "this."){
4846 format = "fm." + format + '(';
4848 format = 'this.call("'+ format.substr(5) + '", ';
4852 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4854 return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4857 // branched to use + in gecko and [].join() in others
4859 body = "this.compiled = function(values){ return '" +
4860 this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4863 body = ["this.compiled = function(values){ return ['"];
4864 body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4865 body.push("'].join('');};");
4866 body = body.join('');
4876 // private function used to call members
4877 call : function(fnName, value, allValues){
4878 return this[fnName](value, allValues);
4882 * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4883 * @param {String/HTMLElement/Roo.Element} el The context element
4884 * @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'})
4885 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4886 * @return {HTMLElement/Roo.Element} The new node or Element
4888 insertFirst: function(el, values, returnElement){
4889 return this.doInsert('afterBegin', el, values, returnElement);
4893 * Applies the supplied values to the template and inserts the new node(s) before el.
4894 * @param {String/HTMLElement/Roo.Element} el The context element
4895 * @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'})
4896 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4897 * @return {HTMLElement/Roo.Element} The new node or Element
4899 insertBefore: function(el, values, returnElement){
4900 return this.doInsert('beforeBegin', el, values, returnElement);
4904 * Applies the supplied values to the template and inserts the new node(s) after el.
4905 * @param {String/HTMLElement/Roo.Element} el The context element
4906 * @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'})
4907 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4908 * @return {HTMLElement/Roo.Element} The new node or Element
4910 insertAfter : function(el, values, returnElement){
4911 return this.doInsert('afterEnd', el, values, returnElement);
4915 * Applies the supplied values to the template and appends the new node(s) to el.
4916 * @param {String/HTMLElement/Roo.Element} el The context element
4917 * @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'})
4918 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4919 * @return {HTMLElement/Roo.Element} The new node or Element
4921 append : function(el, values, returnElement){
4922 return this.doInsert('beforeEnd', el, values, returnElement);
4925 doInsert : function(where, el, values, returnEl){
4926 el = Roo.getDom(el);
4927 var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4928 return returnEl ? Roo.get(newNode, true) : newNode;
4932 * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4933 * @param {String/HTMLElement/Roo.Element} el The context element
4934 * @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'})
4935 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4936 * @return {HTMLElement/Roo.Element} The new node or Element
4938 overwrite : function(el, values, returnElement){
4939 el = Roo.getDom(el);
4940 el.innerHTML = this.applyTemplate(values);
4941 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4945 * Alias for {@link #applyTemplate}
4948 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4951 Roo.DomHelper.Template = Roo.Template;
4954 * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4955 * @param {String/HTMLElement} el A DOM element or its id
4956 * @returns {Roo.Template} The created template
4959 Roo.Template.from = function(el){
4960 el = Roo.getDom(el);
4961 return new Roo.Template(el.value || el.innerHTML);
4964 * Ext JS Library 1.1.1
4965 * Copyright(c) 2006-2007, Ext JS, LLC.
4967 * Originally Released Under LGPL - original licence link has changed is not relivant.
4970 * <script type="text/javascript">
4975 * This is code is also distributed under MIT license for use
4976 * with jQuery and prototype JavaScript libraries.
4979 * @class Roo.DomQuery
4980 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).
4982 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>
4985 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.
4987 <h4>Element Selectors:</h4>
4989 <li> <b>*</b> any element</li>
4990 <li> <b>E</b> an element with the tag E</li>
4991 <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4992 <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4993 <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4994 <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4996 <h4>Attribute Selectors:</h4>
4997 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4999 <li> <b>E[foo]</b> has an attribute "foo"</li>
5000 <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
5001 <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
5002 <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
5003 <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
5004 <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
5005 <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
5007 <h4>Pseudo Classes:</h4>
5009 <li> <b>E:first-child</b> E is the first child of its parent</li>
5010 <li> <b>E:last-child</b> E is the last child of its parent</li>
5011 <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>
5012 <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
5013 <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
5014 <li> <b>E:only-child</b> E is the only child of its parent</li>
5015 <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>
5016 <li> <b>E:first</b> the first E in the resultset</li>
5017 <li> <b>E:last</b> the last E in the resultset</li>
5018 <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
5019 <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
5020 <li> <b>E:even</b> shortcut for :nth-child(even)</li>
5021 <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
5022 <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
5023 <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
5024 <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
5025 <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
5026 <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
5028 <h4>CSS Value Selectors:</h4>
5030 <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
5031 <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
5032 <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
5033 <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
5034 <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
5035 <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
5039 Roo.DomQuery = function(){
5040 var cache = {}, simpleCache = {}, valueCache = {};
5041 var nonSpace = /\S/;
5042 var trimRe = /^\s+|\s+$/g;
5043 var tplRe = /\{(\d+)\}/g;
5044 var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
5045 var tagTokenRe = /^(#)?([\w-\*]+)/;
5046 var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
5048 function child(p, index){
5050 var n = p.firstChild;
5052 if(n.nodeType == 1){
5063 while((n = n.nextSibling) && n.nodeType != 1);
5068 while((n = n.previousSibling) && n.nodeType != 1);
5072 function children(d){
5073 var n = d.firstChild, ni = -1;
5075 var nx = n.nextSibling;
5076 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
5086 function byClassName(c, a, v){
5090 var r = [], ri = -1, cn;
5091 for(var i = 0, ci; ci = c[i]; i++){
5095 ( (ci instanceof SVGElement) ? ci.className.baseVal : ci.className)
5096 +' ').indexOf(v) != -1){
5103 function attrValue(n, attr){
5104 if(!n.tagName && typeof n.length != "undefined"){
5113 if(attr == "class" || attr == "className"){
5114 return (n instanceof SVGElement) ? n.className.baseVal : n.className;
5116 return n.getAttribute(attr) || n[attr];
5120 function getNodes(ns, mode, tagName){
5121 var result = [], ri = -1, cs;
5125 tagName = tagName || "*";
5126 if(typeof ns.getElementsByTagName != "undefined"){
5130 for(var i = 0, ni; ni = ns[i]; i++){
5131 cs = ni.getElementsByTagName(tagName);
5132 for(var j = 0, ci; ci = cs[j]; j++){
5136 }else if(mode == "/" || mode == ">"){
5137 var utag = tagName.toUpperCase();
5138 for(var i = 0, ni, cn; ni = ns[i]; i++){
5139 cn = ni.children || ni.childNodes;
5140 for(var j = 0, cj; cj = cn[j]; j++){
5141 if(cj.nodeName == utag || cj.nodeName == tagName || tagName == '*'){
5146 }else if(mode == "+"){
5147 var utag = tagName.toUpperCase();
5148 for(var i = 0, n; n = ns[i]; i++){
5149 while((n = n.nextSibling) && n.nodeType != 1);
5150 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5154 }else if(mode == "~"){
5155 for(var i = 0, n; n = ns[i]; i++){
5156 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5165 function concat(a, b){
5169 for(var i = 0, l = b.length; i < l; i++){
5175 function byTag(cs, tagName){
5176 if(cs.tagName || cs == document){
5182 var r = [], ri = -1;
5183 tagName = tagName.toLowerCase();
5184 for(var i = 0, ci; ci = cs[i]; i++){
5185 if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5192 function byId(cs, attr, id){
5193 if(cs.tagName || cs == document){
5199 var r = [], ri = -1;
5200 for(var i = 0,ci; ci = cs[i]; i++){
5201 if(ci && ci.id == id){
5209 function byAttribute(cs, attr, value, op, custom){
5210 var r = [], ri = -1, st = custom=="{";
5211 var f = Roo.DomQuery.operators[op];
5212 for(var i = 0, ci; ci = cs[i]; i++){
5215 a = Roo.DomQuery.getStyle(ci, attr);
5217 else if(attr == "class" || attr == "className"){
5218 a = (ci instanceof SVGElement) ? ci.className.baseVal : ci.className;
5219 }else if(attr == "for"){
5221 }else if(attr == "href"){
5222 a = ci.getAttribute("href", 2);
5224 a = ci.getAttribute(attr);
5226 if((f && f(a, value)) || (!f && a)){
5233 function byPseudo(cs, name, value){
5234 return Roo.DomQuery.pseudos[name](cs, value);
5237 // This is for IE MSXML which does not support expandos.
5238 // IE runs the same speed using setAttribute, however FF slows way down
5239 // and Safari completely fails so they need to continue to use expandos.
5240 var isIE = window.ActiveXObject ? true : false;
5242 // this eval is stop the compressor from
5243 // renaming the variable to something shorter
5245 /** eval:var:batch */
5250 function nodupIEXml(cs){
5252 cs[0].setAttribute("_nodup", d);
5254 for(var i = 1, len = cs.length; i < len; i++){
5256 if(!c.getAttribute("_nodup") != d){
5257 c.setAttribute("_nodup", d);
5261 for(var i = 0, len = cs.length; i < len; i++){
5262 cs[i].removeAttribute("_nodup");
5271 var len = cs.length, c, i, r = cs, cj, ri = -1;
5272 if(!len || typeof cs.nodeType != "undefined" || len == 1){
5275 if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5276 return nodupIEXml(cs);
5280 for(i = 1; c = cs[i]; i++){
5285 for(var j = 0; j < i; j++){
5288 for(j = i+1; cj = cs[j]; j++){
5300 function quickDiffIEXml(c1, c2){
5302 for(var i = 0, len = c1.length; i < len; i++){
5303 c1[i].setAttribute("_qdiff", d);
5306 for(var i = 0, len = c2.length; i < len; i++){
5307 if(c2[i].getAttribute("_qdiff") != d){
5308 r[r.length] = c2[i];
5311 for(var i = 0, len = c1.length; i < len; i++){
5312 c1[i].removeAttribute("_qdiff");
5317 function quickDiff(c1, c2){
5318 var len1 = c1.length;
5322 if(isIE && c1[0].selectSingleNode){
5323 return quickDiffIEXml(c1, c2);
5326 for(var i = 0; i < len1; i++){
5330 for(var i = 0, len = c2.length; i < len; i++){
5331 if(c2[i]._qdiff != d){
5332 r[r.length] = c2[i];
5338 function quickId(ns, mode, root, id){
5340 var d = root.ownerDocument || root;
5341 return d.getElementById(id);
5343 ns = getNodes(ns, mode, "*");
5344 return byId(ns, null, id);
5348 getStyle : function(el, name){
5349 return Roo.fly(el).getStyle(name);
5352 * Compiles a selector/xpath query into a reusable function. The returned function
5353 * takes one parameter "root" (optional), which is the context node from where the query should start.
5354 * @param {String} selector The selector/xpath query
5355 * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5356 * @return {Function}
5358 compile : function(path, type){
5359 type = type || "select";
5361 var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5362 var q = path, mode, lq;
5363 var tk = Roo.DomQuery.matchers;
5364 var tklen = tk.length;
5367 // accept leading mode switch
5368 var lmode = q.match(modeRe);
5369 if(lmode && lmode[1]){
5370 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5371 q = q.replace(lmode[1], "");
5373 // strip leading slashes
5374 while(path.substr(0, 1)=="/"){
5375 path = path.substr(1);
5378 while(q && lq != q){
5380 var tm = q.match(tagTokenRe);
5381 if(type == "select"){
5384 fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5386 fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5388 q = q.replace(tm[0], "");
5389 }else if(q.substr(0, 1) != '@'){
5390 fn[fn.length] = 'n = getNodes(n, mode, "*");';
5395 fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5397 fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5399 q = q.replace(tm[0], "");
5402 while(!(mm = q.match(modeRe))){
5403 var matched = false;
5404 for(var j = 0; j < tklen; j++){
5406 var m = q.match(t.re);
5408 fn[fn.length] = t.select.replace(tplRe, function(x, i){
5411 q = q.replace(m[0], "");
5416 // prevent infinite loop on bad selector
5418 throw 'Error parsing selector, parsing failed at "' + q + '"';
5422 fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5423 q = q.replace(mm[1], "");
5426 fn[fn.length] = "return nodup(n);\n}";
5429 * list of variables that need from compression as they are used by eval.
5439 * eval:var:byClassName
5441 * eval:var:byAttribute
5442 * eval:var:attrValue
5450 * Selects a group of elements.
5451 * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5452 * @param {Node} root (optional) The start of the query (defaults to document).
5455 select : function(path, root, type){
5456 if(!root || root == document){
5459 if(typeof root == "string"){
5460 root = document.getElementById(root);
5462 var paths = path.split(",");
5464 for(var i = 0, len = paths.length; i < len; i++){
5465 var p = paths[i].replace(trimRe, "");
5467 cache[p] = Roo.DomQuery.compile(p);
5469 throw p + " is not a valid selector";
5472 var result = cache[p](root);
5473 if(result && result != document){
5474 results = results.concat(result);
5477 if(paths.length > 1){
5478 return nodup(results);
5484 * Selects a single element.
5485 * @param {String} selector The selector/xpath query
5486 * @param {Node} root (optional) The start of the query (defaults to document).
5489 selectNode : function(path, root){
5490 return Roo.DomQuery.select(path, root)[0];
5494 * Selects the value of a node, optionally replacing null with the defaultValue.
5495 * @param {String} selector The selector/xpath query
5496 * @param {Node} root (optional) The start of the query (defaults to document).
5497 * @param {String} defaultValue
5499 selectValue : function(path, root, defaultValue){
5500 path = path.replace(trimRe, "");
5501 if(!valueCache[path]){
5502 valueCache[path] = Roo.DomQuery.compile(path, "select");
5504 var n = valueCache[path](root);
5505 n = n[0] ? n[0] : n;
5506 var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5507 return ((v === null||v === undefined||v==='') ? defaultValue : v);
5511 * Selects the value of a node, parsing integers and floats.
5512 * @param {String} selector The selector/xpath query
5513 * @param {Node} root (optional) The start of the query (defaults to document).
5514 * @param {Number} defaultValue
5517 selectNumber : function(path, root, defaultValue){
5518 var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5519 return parseFloat(v);
5523 * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5524 * @param {String/HTMLElement/Array} el An element id, element or array of elements
5525 * @param {String} selector The simple selector to test
5528 is : function(el, ss){
5529 if(typeof el == "string"){
5530 el = document.getElementById(el);
5532 var isArray = (el instanceof Array);
5533 var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5534 return isArray ? (result.length == el.length) : (result.length > 0);
5538 * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5539 * @param {Array} el An array of elements to filter
5540 * @param {String} selector The simple selector to test
5541 * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5542 * the selector instead of the ones that match
5545 filter : function(els, ss, nonMatches){
5546 ss = ss.replace(trimRe, "");
5547 if(!simpleCache[ss]){
5548 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5550 var result = simpleCache[ss](els);
5551 return nonMatches ? quickDiff(result, els) : result;
5555 * Collection of matching regular expressions and code snippets.
5559 select: 'n = byClassName(n, null, " {1} ");'
5561 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5562 select: 'n = byPseudo(n, "{1}", "{2}");'
5564 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5565 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5568 select: 'n = byId(n, null, "{1}");'
5571 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5576 * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5577 * 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, > <.
5580 "=" : function(a, v){
5583 "!=" : function(a, v){
5586 "^=" : function(a, v){
5587 return a && a.substr(0, v.length) == v;
5589 "$=" : function(a, v){
5590 return a && a.substr(a.length-v.length) == v;
5592 "*=" : function(a, v){
5593 return a && a.indexOf(v) !== -1;
5595 "%=" : function(a, v){
5596 return (a % v) == 0;
5598 "|=" : function(a, v){
5599 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5601 "~=" : function(a, v){
5602 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5607 * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5608 * and the argument (if any) supplied in the selector.
5611 "first-child" : function(c){
5612 var r = [], ri = -1, n;
5613 for(var i = 0, ci; ci = n = c[i]; i++){
5614 while((n = n.previousSibling) && n.nodeType != 1);
5622 "last-child" : function(c){
5623 var r = [], ri = -1, n;
5624 for(var i = 0, ci; ci = n = c[i]; i++){
5625 while((n = n.nextSibling) && n.nodeType != 1);
5633 "nth-child" : function(c, a) {
5634 var r = [], ri = -1;
5635 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5636 var f = (m[1] || 1) - 0, l = m[2] - 0;
5637 for(var i = 0, n; n = c[i]; i++){
5638 var pn = n.parentNode;
5639 if (batch != pn._batch) {
5641 for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5642 if(cn.nodeType == 1){
5649 if (l == 0 || n.nodeIndex == l){
5652 } else if ((n.nodeIndex + l) % f == 0){
5660 "only-child" : function(c){
5661 var r = [], ri = -1;;
5662 for(var i = 0, ci; ci = c[i]; i++){
5663 if(!prev(ci) && !next(ci)){
5670 "empty" : function(c){
5671 var r = [], ri = -1;
5672 for(var i = 0, ci; ci = c[i]; i++){
5673 var cns = ci.childNodes, j = 0, cn, empty = true;
5676 if(cn.nodeType == 1 || cn.nodeType == 3){
5688 "contains" : function(c, v){
5689 var r = [], ri = -1;
5690 for(var i = 0, ci; ci = c[i]; i++){
5691 if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5698 "nodeValue" : function(c, v){
5699 var r = [], ri = -1;
5700 for(var i = 0, ci; ci = c[i]; i++){
5701 if(ci.firstChild && ci.firstChild.nodeValue == v){
5708 "checked" : function(c){
5709 var r = [], ri = -1;
5710 for(var i = 0, ci; ci = c[i]; i++){
5711 if(ci.checked == true){
5718 "not" : function(c, ss){
5719 return Roo.DomQuery.filter(c, ss, true);
5722 "odd" : function(c){
5723 return this["nth-child"](c, "odd");
5726 "even" : function(c){
5727 return this["nth-child"](c, "even");
5730 "nth" : function(c, a){
5731 return c[a-1] || [];
5734 "first" : function(c){
5738 "last" : function(c){
5739 return c[c.length-1] || [];
5742 "has" : function(c, ss){
5743 var s = Roo.DomQuery.select;
5744 var r = [], ri = -1;
5745 for(var i = 0, ci; ci = c[i]; i++){
5746 if(s(ss, ci).length > 0){
5753 "next" : function(c, ss){
5754 var is = Roo.DomQuery.is;
5755 var r = [], ri = -1;
5756 for(var i = 0, ci; ci = c[i]; i++){
5765 "prev" : function(c, ss){
5766 var is = Roo.DomQuery.is;
5767 var r = [], ri = -1;
5768 for(var i = 0, ci; ci = c[i]; i++){
5781 * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5782 * @param {String} path The selector/xpath query
5783 * @param {Node} root (optional) The start of the query (defaults to document).
5788 Roo.query = Roo.DomQuery.select;
5791 * Ext JS Library 1.1.1
5792 * Copyright(c) 2006-2007, Ext JS, LLC.
5794 * Originally Released Under LGPL - original licence link has changed is not relivant.
5797 * <script type="text/javascript">
5801 * @class Roo.util.Observable
5802 * Base class that provides a common interface for publishing events. Subclasses are expected to
5803 * to have a property "events" with all the events defined.<br>
5806 Employee = function(name){
5813 Roo.extend(Employee, Roo.util.Observable);
5815 * @param {Object} config properties to use (incuding events / listeners)
5818 Roo.util.Observable = function(cfg){
5821 this.addEvents(cfg.events || {});
5823 delete cfg.events; // make sure
5826 Roo.apply(this, cfg);
5829 this.on(this.listeners);
5830 delete this.listeners;
5833 Roo.util.Observable.prototype = {
5835 * @cfg {Object} listeners list of events and functions to call for this object,
5839 'click' : function(e) {
5849 * Fires the specified event with the passed parameters (minus the event name).
5850 * @param {String} eventName
5851 * @param {Object...} args Variable number of parameters are passed to handlers
5852 * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5854 fireEvent : function(){
5855 var ce = this.events[arguments[0].toLowerCase()];
5856 if(typeof ce == "object"){
5857 return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5864 filterOptRe : /^(?:scope|delay|buffer|single)$/,
5867 * Appends an event handler to this component
5868 * @param {String} eventName The type of event to listen for
5869 * @param {Function} handler The method the event invokes
5870 * @param {Object} scope (optional) The scope in which to execute the handler
5871 * function. The handler function's "this" context.
5872 * @param {Object} options (optional) An object containing handler configuration
5873 * properties. This may contain any of the following properties:<ul>
5874 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5875 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5876 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5877 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5878 * by the specified number of milliseconds. If the event fires again within that time, the original
5879 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5882 * <b>Combining Options</b><br>
5883 * Using the options argument, it is possible to combine different types of listeners:<br>
5885 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5887 el.on('click', this.onClick, this, {
5894 * <b>Attaching multiple handlers in 1 call</b><br>
5895 * The method also allows for a single argument to be passed which is a config object containing properties
5896 * which specify multiple handlers.
5905 fn: this.onMouseOver,
5909 fn: this.onMouseOut,
5915 * Or a shorthand syntax which passes the same scope object to all handlers:
5918 'click': this.onClick,
5919 'mouseover': this.onMouseOver,
5920 'mouseout': this.onMouseOut,
5925 addListener : function(eventName, fn, scope, o){
5926 if(typeof eventName == "object"){
5929 if(this.filterOptRe.test(e)){
5932 if(typeof o[e] == "function"){
5934 this.addListener(e, o[e], o.scope, o);
5936 // individual options
5937 this.addListener(e, o[e].fn, o[e].scope, o[e]);
5942 o = (!o || typeof o == "boolean") ? {} : o;
5943 eventName = eventName.toLowerCase();
5944 var ce = this.events[eventName] || true;
5945 if(typeof ce == "boolean"){
5946 ce = new Roo.util.Event(this, eventName);
5947 this.events[eventName] = ce;
5949 ce.addListener(fn, scope, o);
5953 * Removes a listener
5954 * @param {String} eventName The type of event to listen for
5955 * @param {Function} handler The handler to remove
5956 * @param {Object} scope (optional) The scope (this object) for the handler
5958 removeListener : function(eventName, fn, scope){
5959 var ce = this.events[eventName.toLowerCase()];
5960 if(typeof ce == "object"){
5961 ce.removeListener(fn, scope);
5966 * Removes all listeners for this object
5968 purgeListeners : function(){
5969 for(var evt in this.events){
5970 if(typeof this.events[evt] == "object"){
5971 this.events[evt].clearListeners();
5976 relayEvents : function(o, events){
5977 var createHandler = function(ename){
5980 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5983 for(var i = 0, len = events.length; i < len; i++){
5984 var ename = events[i];
5985 if(!this.events[ename]){
5986 this.events[ename] = true;
5988 o.on(ename, createHandler(ename), this);
5993 * Used to define events on this Observable
5994 * @param {Object} object The object with the events defined
5996 addEvents : function(o){
6000 Roo.applyIf(this.events, o);
6004 * Checks to see if this object has any listeners for a specified event
6005 * @param {String} eventName The name of the event to check for
6006 * @return {Boolean} True if the event is being listened for, else false
6008 hasListener : function(eventName){
6009 var e = this.events[eventName];
6010 return typeof e == "object" && e.listeners.length > 0;
6014 * Appends an event handler to this element (shorthand for addListener)
6015 * @param {String} eventName The type of event to listen for
6016 * @param {Function} handler The method the event invokes
6017 * @param {Object} scope (optional) The scope in which to execute the handler
6018 * function. The handler function's "this" context.
6019 * @param {Object} options (optional)
6022 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
6024 * Removes a listener (shorthand for removeListener)
6025 * @param {String} eventName The type of event to listen for
6026 * @param {Function} handler The handler to remove
6027 * @param {Object} scope (optional) The scope (this object) for the handler
6030 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
6033 * Starts capture on the specified Observable. All events will be passed
6034 * to the supplied function with the event name + standard signature of the event
6035 * <b>before</b> the event is fired. If the supplied function returns false,
6036 * the event will not fire.
6037 * @param {Observable} o The Observable to capture
6038 * @param {Function} fn The function to call
6039 * @param {Object} scope (optional) The scope (this object) for the fn
6042 Roo.util.Observable.capture = function(o, fn, scope){
6043 o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
6047 * Removes <b>all</b> added captures from the Observable.
6048 * @param {Observable} o The Observable to release
6051 Roo.util.Observable.releaseCapture = function(o){
6052 o.fireEvent = Roo.util.Observable.prototype.fireEvent;
6057 var createBuffered = function(h, o, scope){
6058 var task = new Roo.util.DelayedTask();
6060 task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
6064 var createSingle = function(h, e, fn, scope){
6066 e.removeListener(fn, scope);
6067 return h.apply(scope, arguments);
6071 var createDelayed = function(h, o, scope){
6073 var args = Array.prototype.slice.call(arguments, 0);
6074 setTimeout(function(){
6075 h.apply(scope, args);
6080 Roo.util.Event = function(obj, name){
6083 this.listeners = [];
6086 Roo.util.Event.prototype = {
6087 addListener : function(fn, scope, options){
6088 var o = options || {};
6089 scope = scope || this.obj;
6090 if(!this.isListening(fn, scope)){
6091 var l = {fn: fn, scope: scope, options: o};
6094 h = createDelayed(h, o, scope);
6097 h = createSingle(h, this, fn, scope);
6100 h = createBuffered(h, o, scope);
6103 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
6104 this.listeners.push(l);
6106 this.listeners = this.listeners.slice(0);
6107 this.listeners.push(l);
6112 findListener : function(fn, scope){
6113 scope = scope || this.obj;
6114 var ls = this.listeners;
6115 for(var i = 0, len = ls.length; i < len; i++){
6117 if(l.fn == fn && l.scope == scope){
6124 isListening : function(fn, scope){
6125 return this.findListener(fn, scope) != -1;
6128 removeListener : function(fn, scope){
6130 if((index = this.findListener(fn, scope)) != -1){
6132 this.listeners.splice(index, 1);
6134 this.listeners = this.listeners.slice(0);
6135 this.listeners.splice(index, 1);
6142 clearListeners : function(){
6143 this.listeners = [];
6147 var ls = this.listeners, scope, len = ls.length;
6150 var args = Array.prototype.slice.call(arguments, 0);
6151 for(var i = 0; i < len; i++){
6153 if(l.fireFn.apply(l.scope||this.obj||window, args) === false){
6154 this.firing = false;
6158 this.firing = false;
6165 * Copyright(c) 2007-2017, Roo J Solutions Ltd
6172 * @class Roo.Document
6173 * @extends Roo.util.Observable
6174 * This is a convience class to wrap up the main document loading code.. , rather than adding Roo.onReady(......)
6176 * @param {Object} config the methods and properties of the 'base' class for the application.
6178 * Generic Page handler - implement this to start your app..
6181 * MyProject = new Roo.Document({
6183 'load' : true // your events..
6186 'ready' : function() {
6187 // fired on Roo.onReady()
6192 Roo.Document = function(cfg) {
6197 Roo.util.Observable.call(this,cfg);
6201 Roo.onReady(function() {
6202 _this.fireEvent('ready');
6208 Roo.extend(Roo.Document, Roo.util.Observable, {});/*
6210 * Ext JS Library 1.1.1
6211 * Copyright(c) 2006-2007, Ext JS, LLC.
6213 * Originally Released Under LGPL - original licence link has changed is not relivant.
6216 * <script type="text/javascript">
6220 * @class Roo.EventManager
6221 * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
6222 * several useful events directly.
6223 * See {@link Roo.EventObject} for more details on normalized event objects.
6226 Roo.EventManager = function(){
6227 var docReadyEvent, docReadyProcId, docReadyState = false;
6228 var resizeEvent, resizeTask, textEvent, textSize;
6229 var E = Roo.lib.Event;
6230 var D = Roo.lib.Dom;
6235 var fireDocReady = function(){
6237 docReadyState = true;
6240 clearInterval(docReadyProcId);
6242 if(Roo.isGecko || Roo.isOpera) {
6243 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6246 var defer = document.getElementById("ie-deferred-loader");
6248 defer.onreadystatechange = null;
6249 defer.parentNode.removeChild(defer);
6253 docReadyEvent.fire();
6254 docReadyEvent.clearListeners();
6259 var initDocReady = function(){
6260 docReadyEvent = new Roo.util.Event();
6261 if(Roo.isGecko || Roo.isOpera) {
6262 document.addEventListener("DOMContentLoaded", fireDocReady, false);
6264 document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6265 var defer = document.getElementById("ie-deferred-loader");
6266 defer.onreadystatechange = function(){
6267 if(this.readyState == "complete"){
6271 }else if(Roo.isSafari){
6272 docReadyProcId = setInterval(function(){
6273 var rs = document.readyState;
6274 if(rs == "complete") {
6279 // no matter what, make sure it fires on load
6280 E.on(window, "load", fireDocReady);
6283 var createBuffered = function(h, o){
6284 var task = new Roo.util.DelayedTask(h);
6286 // create new event object impl so new events don't wipe out properties
6287 e = new Roo.EventObjectImpl(e);
6288 task.delay(o.buffer, h, null, [e]);
6292 var createSingle = function(h, el, ename, fn){
6294 Roo.EventManager.removeListener(el, ename, fn);
6299 var createDelayed = function(h, o){
6301 // create new event object impl so new events don't wipe out properties
6302 e = new Roo.EventObjectImpl(e);
6303 setTimeout(function(){
6308 var transitionEndVal = false;
6310 var transitionEnd = function()
6312 if (transitionEndVal) {
6313 return transitionEndVal;
6315 var el = document.createElement('div');
6317 var transEndEventNames = {
6318 WebkitTransition : 'webkitTransitionEnd',
6319 MozTransition : 'transitionend',
6320 OTransition : 'oTransitionEnd otransitionend',
6321 transition : 'transitionend'
6324 for (var name in transEndEventNames) {
6325 if (el.style[name] !== undefined) {
6326 transitionEndVal = transEndEventNames[name];
6327 return transitionEndVal ;
6334 var listen = function(element, ename, opt, fn, scope)
6336 var o = (!opt || typeof opt == "boolean") ? {} : opt;
6337 fn = fn || o.fn; scope = scope || o.scope;
6338 var el = Roo.getDom(element);
6342 throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6345 if (ename == 'transitionend') {
6346 ename = transitionEnd();
6348 var h = function(e){
6349 e = Roo.EventObject.setEvent(e);
6352 t = e.getTarget(o.delegate, el);
6359 if(o.stopEvent === true){
6362 if(o.preventDefault === true){
6365 if(o.stopPropagation === true){
6366 e.stopPropagation();
6369 if(o.normalized === false){
6373 fn.call(scope || el, e, t, o);
6376 h = createDelayed(h, o);
6379 h = createSingle(h, el, ename, fn);
6382 h = createBuffered(h, o);
6385 fn._handlers = fn._handlers || [];
6388 fn._handlers.push([Roo.id(el), ename, h]);
6392 E.on(el, ename, h); // this adds the actuall listener to the object..
6395 if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6396 el.addEventListener("DOMMouseScroll", h, false);
6397 E.on(window, 'unload', function(){
6398 el.removeEventListener("DOMMouseScroll", h, false);
6401 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6402 Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6407 var stopListening = function(el, ename, fn){
6408 var id = Roo.id(el), hds = fn._handlers, hd = fn;
6410 for(var i = 0, len = hds.length; i < len; i++){
6412 if(h[0] == id && h[1] == ename){
6419 E.un(el, ename, hd);
6420 el = Roo.getDom(el);
6421 if(ename == "mousewheel" && el.addEventListener){
6422 el.removeEventListener("DOMMouseScroll", hd, false);
6424 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6425 Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6429 var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6436 * @scope Roo.EventManager
6441 * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6442 * object with a Roo.EventObject
6443 * @param {Function} fn The method the event invokes
6444 * @param {Object} scope An object that becomes the scope of the handler
6445 * @param {boolean} override If true, the obj passed in becomes
6446 * the execution scope of the listener
6447 * @return {Function} The wrapped function
6450 wrap : function(fn, scope, override){
6452 Roo.EventObject.setEvent(e);
6453 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6458 * Appends an event handler to an element (shorthand for addListener)
6459 * @param {String/HTMLElement} element The html element or id to assign the
6460 * @param {String} eventName The type of event to listen for
6461 * @param {Function} handler The method the event invokes
6462 * @param {Object} scope (optional) The scope in which to execute the handler
6463 * function. The handler function's "this" context.
6464 * @param {Object} options (optional) An object containing handler configuration
6465 * properties. This may contain any of the following properties:<ul>
6466 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6467 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6468 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6469 * <li>preventDefault {Boolean} True to prevent the default action</li>
6470 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6471 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6472 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6473 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6474 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6475 * by the specified number of milliseconds. If the event fires again within that time, the original
6476 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6479 * <b>Combining Options</b><br>
6480 * Using the options argument, it is possible to combine different types of listeners:<br>
6482 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6484 el.on('click', this.onClick, this, {
6491 * <b>Attaching multiple handlers in 1 call</b><br>
6492 * The method also allows for a single argument to be passed which is a config object containing properties
6493 * which specify multiple handlers.
6503 fn: this.onMouseOver
6512 * Or a shorthand syntax:<br>
6515 'click' : this.onClick,
6516 'mouseover' : this.onMouseOver,
6517 'mouseout' : this.onMouseOut
6521 addListener : function(element, eventName, fn, scope, options){
6522 if(typeof eventName == "object"){
6528 if(typeof o[e] == "function"){
6530 listen(element, e, o, o[e], o.scope);
6532 // individual options
6533 listen(element, e, o[e]);
6538 return listen(element, eventName, options, fn, scope);
6542 * Removes an event handler
6544 * @param {String/HTMLElement} element The id or html element to remove the
6546 * @param {String} eventName The type of event
6547 * @param {Function} fn
6548 * @return {Boolean} True if a listener was actually removed
6550 removeListener : function(element, eventName, fn){
6551 return stopListening(element, eventName, fn);
6555 * Fires when the document is ready (before onload and before images are loaded). Can be
6556 * accessed shorthanded Roo.onReady().
6557 * @param {Function} fn The method the event invokes
6558 * @param {Object} scope An object that becomes the scope of the handler
6559 * @param {boolean} options
6561 onDocumentReady : function(fn, scope, options){
6562 if(docReadyState){ // if it already fired
6563 docReadyEvent.addListener(fn, scope, options);
6564 docReadyEvent.fire();
6565 docReadyEvent.clearListeners();
6571 docReadyEvent.addListener(fn, scope, options);
6575 * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6576 * @param {Function} fn The method the event invokes
6577 * @param {Object} scope An object that becomes the scope of the handler
6578 * @param {boolean} options
6580 onWindowResize : function(fn, scope, options){
6582 resizeEvent = new Roo.util.Event();
6583 resizeTask = new Roo.util.DelayedTask(function(){
6584 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6586 E.on(window, "resize", function(){
6588 resizeTask.delay(50);
6590 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6594 resizeEvent.addListener(fn, scope, options);
6598 * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6599 * @param {Function} fn The method the event invokes
6600 * @param {Object} scope An object that becomes the scope of the handler
6601 * @param {boolean} options
6603 onTextResize : function(fn, scope, options){
6605 textEvent = new Roo.util.Event();
6606 var textEl = new Roo.Element(document.createElement('div'));
6607 textEl.dom.className = 'x-text-resize';
6608 textEl.dom.innerHTML = 'X';
6609 textEl.appendTo(document.body);
6610 textSize = textEl.dom.offsetHeight;
6611 setInterval(function(){
6612 if(textEl.dom.offsetHeight != textSize){
6613 textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6615 }, this.textResizeInterval);
6617 textEvent.addListener(fn, scope, options);
6621 * Removes the passed window resize listener.
6622 * @param {Function} fn The method the event invokes
6623 * @param {Object} scope The scope of handler
6625 removeResizeListener : function(fn, scope){
6627 resizeEvent.removeListener(fn, scope);
6632 fireResize : function(){
6634 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6638 * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6642 * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6644 textResizeInterval : 50
6649 * @scopeAlias pub=Roo.EventManager
6653 * Appends an event handler to an element (shorthand for addListener)
6654 * @param {String/HTMLElement} element The html element or id to assign the
6655 * @param {String} eventName The type of event to listen for
6656 * @param {Function} handler The method the event invokes
6657 * @param {Object} scope (optional) The scope in which to execute the handler
6658 * function. The handler function's "this" context.
6659 * @param {Object} options (optional) An object containing handler configuration
6660 * properties. This may contain any of the following properties:<ul>
6661 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6662 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6663 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6664 * <li>preventDefault {Boolean} True to prevent the default action</li>
6665 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6666 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6667 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6668 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6669 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6670 * by the specified number of milliseconds. If the event fires again within that time, the original
6671 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6674 * <b>Combining Options</b><br>
6675 * Using the options argument, it is possible to combine different types of listeners:<br>
6677 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6679 el.on('click', this.onClick, this, {
6686 * <b>Attaching multiple handlers in 1 call</b><br>
6687 * The method also allows for a single argument to be passed which is a config object containing properties
6688 * which specify multiple handlers.
6698 fn: this.onMouseOver
6707 * Or a shorthand syntax:<br>
6710 'click' : this.onClick,
6711 'mouseover' : this.onMouseOver,
6712 'mouseout' : this.onMouseOut
6716 pub.on = pub.addListener;
6717 pub.un = pub.removeListener;
6719 pub.stoppedMouseDownEvent = new Roo.util.Event();
6723 * Fires when the document is ready (before onload and before images are loaded). Shorthand of {@link Roo.EventManager#onDocumentReady}.
6724 * @param {Function} fn The method the event invokes
6725 * @param {Object} scope An object that becomes the scope of the handler
6726 * @param {boolean} override If true, the obj passed in becomes
6727 * the execution scope of the listener
6731 Roo.onReady = Roo.EventManager.onDocumentReady;
6733 Roo.onReady(function(){
6734 var bd = Roo.get(document.body);
6739 : Roo.isIE11 ? "roo-ie11"
6740 : Roo.isEdge ? "roo-edge"
6741 : Roo.isGecko ? "roo-gecko"
6742 : Roo.isOpera ? "roo-opera"
6743 : Roo.isSafari ? "roo-safari" : ""];
6746 cls.push("roo-mac");
6749 cls.push("roo-linux");
6752 cls.push("roo-ios");
6755 cls.push("roo-touch");
6757 if(Roo.isBorderBox){
6758 cls.push('roo-border-box');
6760 if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6761 var p = bd.dom.parentNode;
6763 p.className += ' roo-strict';
6766 bd.addClass(cls.join(' '));
6770 * @class Roo.EventObject
6771 * EventObject exposes the Yahoo! UI Event functionality directly on the object
6772 * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code
6775 function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6777 var target = e.getTarget();
6780 var myDiv = Roo.get("myDiv");
6781 myDiv.on("click", handleClick);
6783 Roo.EventManager.on("myDiv", 'click', handleClick);
6784 Roo.EventManager.addListener("myDiv", 'click', handleClick);
6788 Roo.EventObject = function(){
6790 var E = Roo.lib.Event;
6792 // safari keypress events for special keys return bad keycodes
6795 63235 : 39, // right
6798 63276 : 33, // page up
6799 63277 : 34, // page down
6800 63272 : 46, // delete
6805 // normalize button clicks
6806 var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6807 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6809 Roo.EventObjectImpl = function(e){
6811 this.setEvent(e.browserEvent || e);
6814 Roo.EventObjectImpl.prototype = {
6816 * Used to fix doc tools.
6817 * @scope Roo.EventObject.prototype
6823 /** The normal browser event */
6824 browserEvent : null,
6825 /** The button pressed in a mouse event */
6827 /** True if the shift key was down during the event */
6829 /** True if the control key was down during the event */
6831 /** True if the alt key was down during the event */
6890 setEvent : function(e){
6891 if(e == this || (e && e.browserEvent)){ // already wrapped
6894 this.browserEvent = e;
6896 // normalize buttons
6897 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6898 if(e.type == 'click' && this.button == -1){
6902 this.shiftKey = e.shiftKey;
6903 // mac metaKey behaves like ctrlKey
6904 this.ctrlKey = e.ctrlKey || e.metaKey;
6905 this.altKey = e.altKey;
6906 // in getKey these will be normalized for the mac
6907 this.keyCode = e.keyCode;
6908 // keyup warnings on firefox.
6909 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6910 // cache the target for the delayed and or buffered events
6911 this.target = E.getTarget(e);
6913 this.xy = E.getXY(e);
6916 this.shiftKey = false;
6917 this.ctrlKey = false;
6918 this.altKey = false;
6928 * Stop the event (preventDefault and stopPropagation)
6930 stopEvent : function(){
6931 if(this.browserEvent){
6932 if(this.browserEvent.type == 'mousedown'){
6933 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6935 E.stopEvent(this.browserEvent);
6940 * Prevents the browsers default handling of the event.
6942 preventDefault : function(){
6943 if(this.browserEvent){
6944 E.preventDefault(this.browserEvent);
6949 isNavKeyPress : function(){
6950 var k = this.keyCode;
6951 k = Roo.isSafari ? (safariKeys[k] || k) : k;
6952 return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6955 isSpecialKey : function(){
6956 var k = this.keyCode;
6957 return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13 || k == 40 || k == 27 ||
6958 (k == 16) || (k == 17) ||
6959 (k >= 18 && k <= 20) ||
6960 (k >= 33 && k <= 35) ||
6961 (k >= 36 && k <= 39) ||
6962 (k >= 44 && k <= 45);
6965 * Cancels bubbling of the event.
6967 stopPropagation : function(){
6968 if(this.browserEvent){
6969 if(this.type == 'mousedown'){
6970 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6972 E.stopPropagation(this.browserEvent);
6977 * Gets the key code for the event.
6980 getCharCode : function(){
6981 return this.charCode || this.keyCode;
6985 * Returns a normalized keyCode for the event.
6986 * @return {Number} The key code
6988 getKey : function(){
6989 var k = this.keyCode || this.charCode;
6990 return Roo.isSafari ? (safariKeys[k] || k) : k;
6994 * Gets the x coordinate of the event.
6997 getPageX : function(){
7002 * Gets the y coordinate of the event.
7005 getPageY : function(){
7010 * Gets the time of the event.
7013 getTime : function(){
7014 if(this.browserEvent){
7015 return E.getTime(this.browserEvent);
7021 * Gets the page coordinates of the event.
7022 * @return {Array} The xy values like [x, y]
7029 * Gets the target for the event.
7030 * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
7031 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7032 search as a number or element (defaults to 10 || document.body)
7033 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7034 * @return {HTMLelement}
7036 getTarget : function(selector, maxDepth, returnEl){
7037 return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
7040 * Gets the related target.
7041 * @return {HTMLElement}
7043 getRelatedTarget : function(){
7044 if(this.browserEvent){
7045 return E.getRelatedTarget(this.browserEvent);
7051 * Normalizes mouse wheel delta across browsers
7052 * @return {Number} The delta
7054 getWheelDelta : function(){
7055 var e = this.browserEvent;
7057 if(e.wheelDelta){ /* IE/Opera. */
7058 delta = e.wheelDelta/120;
7059 }else if(e.detail){ /* Mozilla case. */
7060 delta = -e.detail/3;
7066 * Returns true if the control, meta, shift or alt key was pressed during this event.
7069 hasModifier : function(){
7070 return !!((this.ctrlKey || this.altKey) || this.shiftKey);
7074 * Returns true if the target of this event equals el or is a child of el
7075 * @param {String/HTMLElement/Element} el
7076 * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
7079 within : function(el, related){
7080 var t = this[related ? "getRelatedTarget" : "getTarget"]();
7081 return t && Roo.fly(el).contains(t);
7084 getPoint : function(){
7085 return new Roo.lib.Point(this.xy[0], this.xy[1]);
7089 return new Roo.EventObjectImpl();
7094 * Ext JS Library 1.1.1
7095 * Copyright(c) 2006-2007, Ext JS, LLC.
7097 * Originally Released Under LGPL - original licence link has changed is not relivant.
7100 * <script type="text/javascript">
7104 // was in Composite Element!??!?!
7107 var D = Roo.lib.Dom;
7108 var E = Roo.lib.Event;
7109 var A = Roo.lib.Anim;
7111 // local style camelizing for speed
7113 var camelRe = /(-[a-z])/gi;
7114 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
7115 var view = document.defaultView;
7118 * @class Roo.Element
7119 * Represents an Element in the DOM.<br><br>
7122 var el = Roo.get("my-div");
7125 var el = getEl("my-div");
7127 // or with a DOM element
7128 var el = Roo.get(myDivElement);
7130 * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
7131 * each call instead of constructing a new one.<br><br>
7132 * <b>Animations</b><br />
7133 * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
7134 * should either be a boolean (true) or an object literal with animation options. The animation options are:
7136 Option Default Description
7137 --------- -------- ---------------------------------------------
7138 duration .35 The duration of the animation in seconds
7139 easing easeOut The YUI easing method
7140 callback none A function to execute when the anim completes
7141 scope this The scope (this) of the callback function
7143 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
7144 * manipulate the animation. Here's an example:
7146 var el = Roo.get("my-div");
7151 // default animation
7152 el.setWidth(100, true);
7154 // animation with some options set
7161 // using the "anim" property to get the Anim object
7167 el.setWidth(100, opt);
7169 if(opt.anim.isAnimated()){
7173 * <b> Composite (Collections of) Elements</b><br />
7174 * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
7175 * @constructor Create a new Element directly.
7176 * @param {String/HTMLElement} element
7177 * @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).
7179 Roo.Element = function(element, forceNew)
7181 var dom = typeof element == "string" ?
7182 document.getElementById(element) : element;
7184 this.listeners = {};
7186 if(!dom){ // invalid id/element
7190 if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
7191 return Roo.Element.cache[id];
7201 * The DOM element ID
7204 this.id = id || Roo.id(dom);
7206 return this; // assumed for cctor?
7209 var El = Roo.Element;
7213 * The element's default display mode (defaults to "")
7216 originalDisplay : "",
7219 // note this is overridden in BS version..
7222 * The default unit to append to CSS values where a unit isn't provided (defaults to px).
7228 * Sets the element's visibility mode. When setVisible() is called it
7229 * will use this to determine whether to set the visibility or the display property.
7230 * @param visMode Element.VISIBILITY or Element.DISPLAY
7231 * @return {Roo.Element} this
7233 setVisibilityMode : function(visMode){
7234 this.visibilityMode = visMode;
7238 * Convenience method for setVisibilityMode(Element.DISPLAY)
7239 * @param {String} display (optional) What to set display to when visible
7240 * @return {Roo.Element} this
7242 enableDisplayMode : function(display){
7243 this.setVisibilityMode(El.DISPLAY);
7244 if(typeof display != "undefined") { this.originalDisplay = display; }
7249 * 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)
7250 * @param {String} selector The simple selector to test
7251 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7252 search as a number or element (defaults to 10 || document.body)
7253 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7254 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7256 findParent : function(simpleSelector, maxDepth, returnEl){
7257 var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7258 maxDepth = maxDepth || 50;
7259 if(typeof maxDepth != "number"){
7260 stopEl = Roo.getDom(maxDepth);
7263 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7264 if(dq.is(p, simpleSelector)){
7265 return returnEl ? Roo.get(p) : p;
7275 * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7276 * @param {String} selector The simple selector to test
7277 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7278 search as a number or element (defaults to 10 || document.body)
7279 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7280 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7282 findParentNode : function(simpleSelector, maxDepth, returnEl){
7283 var p = Roo.fly(this.dom.parentNode, '_internal');
7284 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7288 * Looks at the scrollable parent element
7290 findScrollableParent : function()
7292 var overflowRegex = /(auto|scroll)/;
7294 if(this.getStyle('position') === 'fixed'){
7295 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7298 var excludeStaticParent = this.getStyle('position') === "absolute";
7300 for (var parent = this; (parent = Roo.get(parent.dom.parentNode));){
7302 if (excludeStaticParent && parent.getStyle('position') === "static") {
7306 if (overflowRegex.test(parent.getStyle('overflow') + parent.getStyle('overflow-x') + parent.getStyle('overflow-y'))){
7310 if(parent.dom.nodeName.toLowerCase() == 'body'){
7311 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7315 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7319 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7320 * This is a shortcut for findParentNode() that always returns an Roo.Element.
7321 * @param {String} selector The simple selector to test
7322 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7323 search as a number or element (defaults to 10 || document.body)
7324 * @return {Roo.Element} The matching DOM node (or null if no match was found)
7326 up : function(simpleSelector, maxDepth){
7327 return this.findParentNode(simpleSelector, maxDepth, true);
7333 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7334 * @param {String} selector The simple selector to test
7335 * @return {Boolean} True if this element matches the selector, else false
7337 is : function(simpleSelector){
7338 return Roo.DomQuery.is(this.dom, simpleSelector);
7342 * Perform animation on this element.
7343 * @param {Object} args The YUI animation control args
7344 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7345 * @param {Function} onComplete (optional) Function to call when animation completes
7346 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7347 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7348 * @return {Roo.Element} this
7350 animate : function(args, duration, onComplete, easing, animType){
7351 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7356 * @private Internal animation call
7358 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7359 animType = animType || 'run';
7361 var anim = Roo.lib.Anim[animType](
7363 (opt.duration || defaultDur) || .35,
7364 (opt.easing || defaultEase) || 'easeOut',
7366 Roo.callback(cb, this);
7367 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7375 // private legacy anim prep
7376 preanim : function(a, i){
7377 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7381 * Removes worthless text nodes
7382 * @param {Boolean} forceReclean (optional) By default the element
7383 * keeps track if it has been cleaned already so
7384 * you can call this over and over. However, if you update the element and
7385 * need to force a reclean, you can pass true.
7387 clean : function(forceReclean){
7388 if(this.isCleaned && forceReclean !== true){
7392 var d = this.dom, n = d.firstChild, ni = -1;
7394 var nx = n.nextSibling;
7395 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7402 this.isCleaned = true;
7407 calcOffsetsTo : function(el){
7410 var restorePos = false;
7411 if(el.getStyle('position') == 'static'){
7412 el.position('relative');
7417 while(op && op != d && op.tagName != 'HTML'){
7420 op = op.offsetParent;
7423 el.position('static');
7429 * Scrolls this element into view within the passed container.
7430 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7431 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7432 * @return {Roo.Element} this
7434 scrollIntoView : function(container, hscroll){
7435 var c = Roo.getDom(container) || document.body;
7438 var o = this.calcOffsetsTo(c),
7441 b = t+el.offsetHeight,
7442 r = l+el.offsetWidth;
7444 var ch = c.clientHeight;
7445 var ct = parseInt(c.scrollTop, 10);
7446 var cl = parseInt(c.scrollLeft, 10);
7448 var cr = cl + c.clientWidth;
7456 if(hscroll !== false){
7460 c.scrollLeft = r-c.clientWidth;
7467 scrollChildIntoView : function(child, hscroll){
7468 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7472 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7473 * the new height may not be available immediately.
7474 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7475 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7476 * @param {Function} onComplete (optional) Function to call when animation completes
7477 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7478 * @return {Roo.Element} this
7480 autoHeight : function(animate, duration, onComplete, easing){
7481 var oldHeight = this.getHeight();
7483 this.setHeight(1); // force clipping
7484 setTimeout(function(){
7485 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7487 this.setHeight(height);
7489 if(typeof onComplete == "function"){
7493 this.setHeight(oldHeight); // restore original height
7494 this.setHeight(height, animate, duration, function(){
7496 if(typeof onComplete == "function") { onComplete(); }
7497 }.createDelegate(this), easing);
7499 }.createDelegate(this), 0);
7504 * Returns true if this element is an ancestor of the passed element
7505 * @param {HTMLElement/String} el The element to check
7506 * @return {Boolean} True if this element is an ancestor of el, else false
7508 contains : function(el){
7509 if(!el){return false;}
7510 return D.isAncestor(this.dom, el.dom ? el.dom : el);
7514 * Checks whether the element is currently visible using both visibility and display properties.
7515 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7516 * @return {Boolean} True if the element is currently visible, else false
7518 isVisible : function(deep) {
7519 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7520 if(deep !== true || !vis){
7523 var p = this.dom.parentNode;
7524 while(p && p.tagName.toLowerCase() != "body"){
7525 if(!Roo.fly(p, '_isVisible').isVisible()){
7534 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7535 * @param {String} selector The CSS selector
7536 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7537 * @return {CompositeElement/CompositeElementLite} The composite element
7539 select : function(selector, unique){
7540 return El.select(selector, unique, this.dom);
7544 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7545 * @param {String} selector The CSS selector
7546 * @return {Array} An array of the matched nodes
7548 query : function(selector, unique){
7549 return Roo.DomQuery.select(selector, this.dom);
7553 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7554 * @param {String} selector The CSS selector
7555 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7556 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7558 child : function(selector, returnDom){
7559 var n = Roo.DomQuery.selectNode(selector, this.dom);
7560 return returnDom ? n : Roo.get(n);
7564 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7565 * @param {String} selector The CSS selector
7566 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7567 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7569 down : function(selector, returnDom){
7570 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7571 return returnDom ? n : Roo.get(n);
7575 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7576 * @param {String} group The group the DD object is member of
7577 * @param {Object} config The DD config object
7578 * @param {Object} overrides An object containing methods to override/implement on the DD object
7579 * @return {Roo.dd.DD} The DD object
7581 initDD : function(group, config, overrides){
7582 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7583 return Roo.apply(dd, overrides);
7587 * Initializes a {@link Roo.dd.DDProxy} object for this element.
7588 * @param {String} group The group the DDProxy object is member of
7589 * @param {Object} config The DDProxy config object
7590 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7591 * @return {Roo.dd.DDProxy} The DDProxy object
7593 initDDProxy : function(group, config, overrides){
7594 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7595 return Roo.apply(dd, overrides);
7599 * Initializes a {@link Roo.dd.DDTarget} object for this element.
7600 * @param {String} group The group the DDTarget object is member of
7601 * @param {Object} config The DDTarget config object
7602 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7603 * @return {Roo.dd.DDTarget} The DDTarget object
7605 initDDTarget : function(group, config, overrides){
7606 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7607 return Roo.apply(dd, overrides);
7611 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7612 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7613 * @param {Boolean} visible Whether the element is visible
7614 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7615 * @return {Roo.Element} this
7617 setVisible : function(visible, animate){
7619 if(this.visibilityMode == El.DISPLAY){
7620 this.setDisplayed(visible);
7623 this.dom.style.visibility = visible ? "visible" : "hidden";
7626 // closure for composites
7628 var visMode = this.visibilityMode;
7630 this.setOpacity(.01);
7631 this.setVisible(true);
7633 this.anim({opacity: { to: (visible?1:0) }},
7634 this.preanim(arguments, 1),
7635 null, .35, 'easeIn', function(){
7637 if(visMode == El.DISPLAY){
7638 dom.style.display = "none";
7640 dom.style.visibility = "hidden";
7642 Roo.get(dom).setOpacity(1);
7650 * Returns true if display is not "none"
7653 isDisplayed : function() {
7654 return this.getStyle("display") != "none";
7658 * Toggles the element's visibility or display, depending on visibility mode.
7659 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7660 * @return {Roo.Element} this
7662 toggle : function(animate){
7663 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7668 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7669 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7670 * @return {Roo.Element} this
7672 setDisplayed : function(value) {
7673 if(typeof value == "boolean"){
7674 value = value ? this.originalDisplay : "none";
7676 this.setStyle("display", value);
7681 * Tries to focus the element. Any exceptions are caught and ignored.
7682 * @return {Roo.Element} this
7684 focus : function() {
7692 * Tries to blur the element. Any exceptions are caught and ignored.
7693 * @return {Roo.Element} this
7703 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7704 * @param {String/Array} className The CSS class to add, or an array of classes
7705 * @return {Roo.Element} this
7707 addClass : function(className){
7708 if(className instanceof Array){
7709 for(var i = 0, len = className.length; i < len; i++) {
7710 this.addClass(className[i]);
7713 if(className && !this.hasClass(className)){
7714 if (this.dom instanceof SVGElement) {
7715 this.dom.className.baseVal =this.dom.className.baseVal + " " + className;
7717 this.dom.className = this.dom.className + " " + className;
7725 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7726 * @param {String/Array} className The CSS class to add, or an array of classes
7727 * @return {Roo.Element} this
7729 radioClass : function(className){
7730 var siblings = this.dom.parentNode.childNodes;
7731 for(var i = 0; i < siblings.length; i++) {
7732 var s = siblings[i];
7733 if(s.nodeType == 1){
7734 Roo.get(s).removeClass(className);
7737 this.addClass(className);
7742 * Removes one or more CSS classes from the element.
7743 * @param {String/Array} className The CSS class to remove, or an array of classes
7744 * @return {Roo.Element} this
7746 removeClass : function(className){
7748 var cn = this.dom instanceof SVGElement ? this.dom.className.baseVal : this.dom.className;
7749 if(!className || !cn){
7752 if(className instanceof Array){
7753 for(var i = 0, len = className.length; i < len; i++) {
7754 this.removeClass(className[i]);
7757 if(this.hasClass(className)){
7758 var re = this.classReCache[className];
7760 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7761 this.classReCache[className] = re;
7763 if (this.dom instanceof SVGElement) {
7764 this.dom.className.baseVal = cn.replace(re, " ");
7766 this.dom.className = cn.replace(re, " ");
7777 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7778 * @param {String} className The CSS class to toggle
7779 * @return {Roo.Element} this
7781 toggleClass : function(className){
7782 if(this.hasClass(className)){
7783 this.removeClass(className);
7785 this.addClass(className);
7791 * Checks if the specified CSS class exists on this element's DOM node.
7792 * @param {String} className The CSS class to check for
7793 * @return {Boolean} True if the class exists, else false
7795 hasClass : function(className){
7796 if (this.dom instanceof SVGElement) {
7797 return className && (' '+this.dom.className.baseVal +' ').indexOf(' '+className+' ') != -1;
7799 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7803 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
7804 * @param {String} oldClassName The CSS class to replace
7805 * @param {String} newClassName The replacement CSS class
7806 * @return {Roo.Element} this
7808 replaceClass : function(oldClassName, newClassName){
7809 this.removeClass(oldClassName);
7810 this.addClass(newClassName);
7815 * Returns an object with properties matching the styles requested.
7816 * For example, el.getStyles('color', 'font-size', 'width') might return
7817 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7818 * @param {String} style1 A style name
7819 * @param {String} style2 A style name
7820 * @param {String} etc.
7821 * @return {Object} The style object
7823 getStyles : function(){
7824 var a = arguments, len = a.length, r = {};
7825 for(var i = 0; i < len; i++){
7826 r[a[i]] = this.getStyle(a[i]);
7832 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7833 * @param {String} property The style property whose value is returned.
7834 * @return {String} The current value of the style property for this element.
7836 getStyle : function(){
7837 return view && view.getComputedStyle ?
7839 var el = this.dom, v, cs, camel;
7840 if(prop == 'float'){
7843 if(el.style && (v = el.style[prop])){
7846 if(cs = view.getComputedStyle(el, "")){
7847 if(!(camel = propCache[prop])){
7848 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7855 var el = this.dom, v, cs, camel;
7856 if(prop == 'opacity'){
7857 if(typeof el.style.filter == 'string'){
7858 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7860 var fv = parseFloat(m[1]);
7862 return fv ? fv / 100 : 0;
7867 }else if(prop == 'float'){
7868 prop = "styleFloat";
7870 if(!(camel = propCache[prop])){
7871 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7873 if(v = el.style[camel]){
7876 if(cs = el.currentStyle){
7884 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7885 * @param {String/Object} property The style property to be set, or an object of multiple styles.
7886 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7887 * @return {Roo.Element} this
7889 setStyle : function(prop, value){
7890 if(typeof prop == "string"){
7892 if (prop == 'float') {
7893 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
7898 if(!(camel = propCache[prop])){
7899 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7902 if(camel == 'opacity') {
7903 this.setOpacity(value);
7905 this.dom.style[camel] = value;
7908 for(var style in prop){
7909 if(typeof prop[style] != "function"){
7910 this.setStyle(style, prop[style]);
7918 * More flexible version of {@link #setStyle} for setting style properties.
7919 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7920 * a function which returns such a specification.
7921 * @return {Roo.Element} this
7923 applyStyles : function(style){
7924 Roo.DomHelper.applyStyles(this.dom, style);
7929 * 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).
7930 * @return {Number} The X position of the element
7933 return D.getX(this.dom);
7937 * 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).
7938 * @return {Number} The Y position of the element
7941 return D.getY(this.dom);
7945 * 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).
7946 * @return {Array} The XY position of the element
7949 return D.getXY(this.dom);
7953 * 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).
7954 * @param {Number} The X position of the element
7955 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7956 * @return {Roo.Element} this
7958 setX : function(x, animate){
7960 D.setX(this.dom, x);
7962 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7968 * 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).
7969 * @param {Number} The Y position of the element
7970 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7971 * @return {Roo.Element} this
7973 setY : function(y, animate){
7975 D.setY(this.dom, y);
7977 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7983 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7984 * @param {String} left The left CSS property value
7985 * @return {Roo.Element} this
7987 setLeft : function(left){
7988 this.setStyle("left", this.addUnits(left));
7993 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7994 * @param {String} top The top CSS property value
7995 * @return {Roo.Element} this
7997 setTop : function(top){
7998 this.setStyle("top", this.addUnits(top));
8003 * Sets the element's CSS right style.
8004 * @param {String} right The right CSS property value
8005 * @return {Roo.Element} this
8007 setRight : function(right){
8008 this.setStyle("right", this.addUnits(right));
8013 * Sets the element's CSS bottom style.
8014 * @param {String} bottom The bottom CSS property value
8015 * @return {Roo.Element} this
8017 setBottom : function(bottom){
8018 this.setStyle("bottom", this.addUnits(bottom));
8023 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
8024 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
8025 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
8026 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8027 * @return {Roo.Element} this
8029 setXY : function(pos, animate){
8031 D.setXY(this.dom, pos);
8033 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
8039 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
8040 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
8041 * @param {Number} x X value for new position (coordinates are page-based)
8042 * @param {Number} y Y value for new position (coordinates are page-based)
8043 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8044 * @return {Roo.Element} this
8046 setLocation : function(x, y, animate){
8047 this.setXY([x, y], this.preanim(arguments, 2));
8052 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
8053 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
8054 * @param {Number} x X value for new position (coordinates are page-based)
8055 * @param {Number} y Y value for new position (coordinates are page-based)
8056 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8057 * @return {Roo.Element} this
8059 moveTo : function(x, y, animate){
8060 this.setXY([x, y], this.preanim(arguments, 2));
8065 * Returns the region of the given element.
8066 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
8067 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
8069 getRegion : function(){
8070 return D.getRegion(this.dom);
8074 * Returns the offset height of the element
8075 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
8076 * @return {Number} The element's height
8078 getHeight : function(contentHeight){
8079 var h = this.dom.offsetHeight || 0;
8080 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
8084 * Returns the offset width of the element
8085 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
8086 * @return {Number} The element's width
8088 getWidth : function(contentWidth){
8089 var w = this.dom.offsetWidth || 0;
8090 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
8094 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
8095 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
8096 * if a height has not been set using CSS.
8099 getComputedHeight : function(){
8100 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
8102 h = parseInt(this.getStyle('height'), 10) || 0;
8103 if(!this.isBorderBox()){
8104 h += this.getFrameWidth('tb');
8111 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
8112 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
8113 * if a width has not been set using CSS.
8116 getComputedWidth : function(){
8117 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
8119 w = parseInt(this.getStyle('width'), 10) || 0;
8120 if(!this.isBorderBox()){
8121 w += this.getFrameWidth('lr');
8128 * Returns the size of the element.
8129 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
8130 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
8132 getSize : function(contentSize){
8133 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
8137 * Returns the width and height of the viewport.
8138 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
8140 getViewSize : function(){
8141 var d = this.dom, doc = document, aw = 0, ah = 0;
8142 if(d == doc || d == doc.body){
8143 return {width : D.getViewWidth(), height: D.getViewHeight()};
8146 width : d.clientWidth,
8147 height: d.clientHeight
8153 * Returns the value of the "value" attribute
8154 * @param {Boolean} asNumber true to parse the value as a number
8155 * @return {String/Number}
8157 getValue : function(asNumber){
8158 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
8162 adjustWidth : function(width){
8163 if(typeof width == "number"){
8164 if(this.autoBoxAdjust && !this.isBorderBox()){
8165 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8175 adjustHeight : function(height){
8176 if(typeof height == "number"){
8177 if(this.autoBoxAdjust && !this.isBorderBox()){
8178 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8188 * Set the width of the element
8189 * @param {Number} width The new width
8190 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8191 * @return {Roo.Element} this
8193 setWidth : function(width, animate){
8194 width = this.adjustWidth(width);
8196 this.dom.style.width = this.addUnits(width);
8198 this.anim({width: {to: width}}, this.preanim(arguments, 1));
8204 * Set the height of the element
8205 * @param {Number} height The new height
8206 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8207 * @return {Roo.Element} this
8209 setHeight : function(height, animate){
8210 height = this.adjustHeight(height);
8212 this.dom.style.height = this.addUnits(height);
8214 this.anim({height: {to: height}}, this.preanim(arguments, 1));
8220 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
8221 * @param {Number} width The new width
8222 * @param {Number} height The new height
8223 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8224 * @return {Roo.Element} this
8226 setSize : function(width, height, animate){
8227 if(typeof width == "object"){ // in case of object from getSize()
8228 height = width.height; width = width.width;
8230 width = this.adjustWidth(width); height = this.adjustHeight(height);
8232 this.dom.style.width = this.addUnits(width);
8233 this.dom.style.height = this.addUnits(height);
8235 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
8241 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
8242 * @param {Number} x X value for new position (coordinates are page-based)
8243 * @param {Number} y Y value for new position (coordinates are page-based)
8244 * @param {Number} width The new width
8245 * @param {Number} height The new height
8246 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8247 * @return {Roo.Element} this
8249 setBounds : function(x, y, width, height, animate){
8251 this.setSize(width, height);
8252 this.setLocation(x, y);
8254 width = this.adjustWidth(width); height = this.adjustHeight(height);
8255 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
8256 this.preanim(arguments, 4), 'motion');
8262 * 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.
8263 * @param {Roo.lib.Region} region The region to fill
8264 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8265 * @return {Roo.Element} this
8267 setRegion : function(region, animate){
8268 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
8273 * Appends an event handler
8275 * @param {String} eventName The type of event to append
8276 * @param {Function} fn The method the event invokes
8277 * @param {Object} scope (optional) The scope (this object) of the fn
8278 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
8280 addListener : function(eventName, fn, scope, options)
8282 if (eventName == 'dblclick') { // doublclick (touchstart) - faked on touch.
8283 this.addListener('touchstart', this.onTapHandler, this);
8286 // we need to handle a special case where dom element is a svg element.
8287 // in this case we do not actua
8292 if (this.dom instanceof SVGElement && !(this.dom instanceof SVGSVGElement)) {
8293 if (typeof(this.listeners[eventName]) == 'undefined') {
8294 this.listeners[eventName] = new Roo.util.Event(this, eventName);
8296 this.listeners[eventName].addListener(fn, scope, options);
8301 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
8306 onTapHandler : function(event)
8308 if(!this.tapedTwice) {
8309 this.tapedTwice = true;
8311 setTimeout( function() {
8312 s.tapedTwice = false;
8316 event.preventDefault();
8317 var revent = new MouseEvent('dblclick', {
8323 this.dom.dispatchEvent(revent);
8324 //action on double tap goes below
8329 * Removes an event handler from this element
8330 * @param {String} eventName the type of event to remove
8331 * @param {Function} fn the method the event invokes
8332 * @param {Function} scope (needed for svg fake listeners)
8333 * @return {Roo.Element} this
8335 removeListener : function(eventName, fn, scope){
8336 Roo.EventManager.removeListener(this.dom, eventName, fn);
8337 if (typeof(this.listeners) == 'undefined' || typeof(this.listeners[eventName]) == 'undefined') {
8340 this.listeners[eventName].removeListener(fn, scope);
8345 * Removes all previous added listeners from this element
8346 * @return {Roo.Element} this
8348 removeAllListeners : function(){
8349 E.purgeElement(this.dom);
8350 this.listeners = {};
8354 relayEvent : function(eventName, observable){
8355 this.on(eventName, function(e){
8356 observable.fireEvent(eventName, e);
8362 * Set the opacity of the element
8363 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8364 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8365 * @return {Roo.Element} this
8367 setOpacity : function(opacity, animate){
8369 var s = this.dom.style;
8372 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8373 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8375 s.opacity = opacity;
8378 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8384 * Gets the left X coordinate
8385 * @param {Boolean} local True to get the local css position instead of page coordinate
8388 getLeft : function(local){
8392 return parseInt(this.getStyle("left"), 10) || 0;
8397 * Gets the right X coordinate of the element (element X position + element width)
8398 * @param {Boolean} local True to get the local css position instead of page coordinate
8401 getRight : function(local){
8403 return this.getX() + this.getWidth();
8405 return (this.getLeft(true) + this.getWidth()) || 0;
8410 * Gets the top Y coordinate
8411 * @param {Boolean} local True to get the local css position instead of page coordinate
8414 getTop : function(local) {
8418 return parseInt(this.getStyle("top"), 10) || 0;
8423 * Gets the bottom Y coordinate of the element (element Y position + element height)
8424 * @param {Boolean} local True to get the local css position instead of page coordinate
8427 getBottom : function(local){
8429 return this.getY() + this.getHeight();
8431 return (this.getTop(true) + this.getHeight()) || 0;
8436 * Initializes positioning on this element. If a desired position is not passed, it will make the
8437 * the element positioned relative IF it is not already positioned.
8438 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8439 * @param {Number} zIndex (optional) The zIndex to apply
8440 * @param {Number} x (optional) Set the page X position
8441 * @param {Number} y (optional) Set the page Y position
8443 position : function(pos, zIndex, x, y){
8445 if(this.getStyle('position') == 'static'){
8446 this.setStyle('position', 'relative');
8449 this.setStyle("position", pos);
8452 this.setStyle("z-index", zIndex);
8454 if(x !== undefined && y !== undefined){
8456 }else if(x !== undefined){
8458 }else if(y !== undefined){
8464 * Clear positioning back to the default when the document was loaded
8465 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8466 * @return {Roo.Element} this
8468 clearPositioning : function(value){
8476 "position" : "static"
8482 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8483 * snapshot before performing an update and then restoring the element.
8486 getPositioning : function(){
8487 var l = this.getStyle("left");
8488 var t = this.getStyle("top");
8490 "position" : this.getStyle("position"),
8492 "right" : l ? "" : this.getStyle("right"),
8494 "bottom" : t ? "" : this.getStyle("bottom"),
8495 "z-index" : this.getStyle("z-index")
8500 * Gets the width of the border(s) for the specified side(s)
8501 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8502 * passing lr would get the border (l)eft width + the border (r)ight width.
8503 * @return {Number} The width of the sides passed added together
8505 getBorderWidth : function(side){
8506 return this.addStyles(side, El.borders);
8510 * Gets the width of the padding(s) for the specified side(s)
8511 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8512 * passing lr would get the padding (l)eft + the padding (r)ight.
8513 * @return {Number} The padding of the sides passed added together
8515 getPadding : function(side){
8516 return this.addStyles(side, El.paddings);
8520 * Set positioning with an object returned by getPositioning().
8521 * @param {Object} posCfg
8522 * @return {Roo.Element} this
8524 setPositioning : function(pc){
8525 this.applyStyles(pc);
8526 if(pc.right == "auto"){
8527 this.dom.style.right = "";
8529 if(pc.bottom == "auto"){
8530 this.dom.style.bottom = "";
8536 fixDisplay : function(){
8537 if(this.getStyle("display") == "none"){
8538 this.setStyle("visibility", "hidden");
8539 this.setStyle("display", this.originalDisplay); // first try reverting to default
8540 if(this.getStyle("display") == "none"){ // if that fails, default to block
8541 this.setStyle("display", "block");
8547 * Quick set left and top adding default units
8548 * @param {String} left The left CSS property value
8549 * @param {String} top The top CSS property value
8550 * @return {Roo.Element} this
8552 setLeftTop : function(left, top){
8553 this.dom.style.left = this.addUnits(left);
8554 this.dom.style.top = this.addUnits(top);
8559 * Move this element relative to its current position.
8560 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8561 * @param {Number} distance How far to move the element in pixels
8562 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8563 * @return {Roo.Element} this
8565 move : function(direction, distance, animate){
8566 var xy = this.getXY();
8567 direction = direction.toLowerCase();
8571 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8575 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8580 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8585 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8592 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8593 * @return {Roo.Element} this
8596 if(!this.isClipped){
8597 this.isClipped = true;
8598 this.originalClip = {
8599 "o": this.getStyle("overflow"),
8600 "x": this.getStyle("overflow-x"),
8601 "y": this.getStyle("overflow-y")
8603 this.setStyle("overflow", "hidden");
8604 this.setStyle("overflow-x", "hidden");
8605 this.setStyle("overflow-y", "hidden");
8611 * Return clipping (overflow) to original clipping before clip() was called
8612 * @return {Roo.Element} this
8614 unclip : function(){
8616 this.isClipped = false;
8617 var o = this.originalClip;
8618 if(o.o){this.setStyle("overflow", o.o);}
8619 if(o.x){this.setStyle("overflow-x", o.x);}
8620 if(o.y){this.setStyle("overflow-y", o.y);}
8627 * Gets the x,y coordinates specified by the anchor position on the element.
8628 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
8629 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8630 * {width: (target width), height: (target height)} (defaults to the element's current size)
8631 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8632 * @return {Array} [x, y] An array containing the element's x and y coordinates
8634 getAnchorXY : function(anchor, local, s){
8635 //Passing a different size is useful for pre-calculating anchors,
8636 //especially for anchored animations that change the el size.
8638 var w, h, vp = false;
8641 if(d == document.body || d == document){
8643 w = D.getViewWidth(); h = D.getViewHeight();
8645 w = this.getWidth(); h = this.getHeight();
8648 w = s.width; h = s.height;
8650 var x = 0, y = 0, r = Math.round;
8651 switch((anchor || "tl").toLowerCase()){
8693 var sc = this.getScroll();
8694 return [x + sc.left, y + sc.top];
8696 //Add the element's offset xy
8697 var o = this.getXY();
8698 return [x+o[0], y+o[1]];
8702 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8703 * supported position values.
8704 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8705 * @param {String} position The position to align to.
8706 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8707 * @return {Array} [x, y]
8709 getAlignToXY : function(el, p, o)
8714 throw "Element.alignTo with an element that doesn't exist";
8716 var c = false; //constrain to viewport
8717 var p1 = "", p2 = "";
8724 }else if(p.indexOf("-") == -1){
8727 p = p.toLowerCase();
8728 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8730 throw "Element.alignTo with an invalid alignment " + p;
8732 p1 = m[1]; p2 = m[2]; c = !!m[3];
8734 //Subtract the aligned el's internal xy from the target's offset xy
8735 //plus custom offset to get the aligned el's new offset xy
8736 var a1 = this.getAnchorXY(p1, true);
8737 var a2 = el.getAnchorXY(p2, false);
8738 var x = a2[0] - a1[0] + o[0];
8739 var y = a2[1] - a1[1] + o[1];
8741 //constrain the aligned el to viewport if necessary
8742 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8743 // 5px of margin for ie
8744 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8746 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8747 //perpendicular to the vp border, allow the aligned el to slide on that border,
8748 //otherwise swap the aligned el to the opposite border of the target.
8749 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8750 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8751 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t") );
8752 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8755 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8756 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8758 if((x+w) > dw + scrollX){
8759 x = swapX ? r.left-w : dw+scrollX-w;
8762 x = swapX ? r.right : scrollX;
8764 if((y+h) > dh + scrollY){
8765 y = swapY ? r.top-h : dh+scrollY-h;
8768 y = swapY ? r.bottom : scrollY;
8775 getConstrainToXY : function(){
8776 var os = {top:0, left:0, bottom:0, right: 0};
8778 return function(el, local, offsets, proposedXY){
8780 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8782 var vw, vh, vx = 0, vy = 0;
8783 if(el.dom == document.body || el.dom == document){
8784 vw = Roo.lib.Dom.getViewWidth();
8785 vh = Roo.lib.Dom.getViewHeight();
8787 vw = el.dom.clientWidth;
8788 vh = el.dom.clientHeight;
8790 var vxy = el.getXY();
8796 var s = el.getScroll();
8798 vx += offsets.left + s.left;
8799 vy += offsets.top + s.top;
8801 vw -= offsets.right;
8802 vh -= offsets.bottom;
8807 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8808 var x = xy[0], y = xy[1];
8809 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8811 // only move it if it needs it
8814 // first validate right/bottom
8823 // then make sure top/left isn't negative
8832 return moved ? [x, y] : false;
8837 adjustForConstraints : function(xy, parent, offsets){
8838 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
8842 * Aligns this element with another element relative to the specified anchor points. If the other element is the
8843 * document it aligns it to the viewport.
8844 * The position parameter is optional, and can be specified in any one of the following formats:
8846 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8847 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8848 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
8849 * deprecated in favor of the newer two anchor syntax below</i>.</li>
8850 * <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
8851 * element's anchor point, and the second value is used as the target's anchor point.</li>
8853 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
8854 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8855 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
8856 * that specified in order to enforce the viewport constraints.
8857 * Following are all of the supported anchor positions:
8860 ----- -----------------------------
8861 tl The top left corner (default)
8862 t The center of the top edge
8863 tr The top right corner
8864 l The center of the left edge
8865 c In the center of the element
8866 r The center of the right edge
8867 bl The bottom left corner
8868 b The center of the bottom edge
8869 br The bottom right corner
8873 // align el to other-el using the default positioning ("tl-bl", non-constrained)
8874 el.alignTo("other-el");
8876 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8877 el.alignTo("other-el", "tr?");
8879 // align the bottom right corner of el with the center left edge of other-el
8880 el.alignTo("other-el", "br-l?");
8882 // align the center of el with the bottom left corner of other-el and
8883 // adjust the x position by -6 pixels (and the y position by 0)
8884 el.alignTo("other-el", "c-bl", [-6, 0]);
8886 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8887 * @param {String} position The position to align to.
8888 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8889 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8890 * @return {Roo.Element} this
8892 alignTo : function(element, position, offsets, animate){
8893 var xy = this.getAlignToXY(element, position, offsets);
8894 this.setXY(xy, this.preanim(arguments, 3));
8899 * Anchors an element to another element and realigns it when the window is resized.
8900 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8901 * @param {String} position The position to align to.
8902 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8903 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8904 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8905 * is a number, it is used as the buffer delay (defaults to 50ms).
8906 * @param {Function} callback The function to call after the animation finishes
8907 * @return {Roo.Element} this
8909 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8910 var action = function(){
8911 this.alignTo(el, alignment, offsets, animate);
8912 Roo.callback(callback, this);
8914 Roo.EventManager.onWindowResize(action, this);
8915 var tm = typeof monitorScroll;
8916 if(tm != 'undefined'){
8917 Roo.EventManager.on(window, 'scroll', action, this,
8918 {buffer: tm == 'number' ? monitorScroll : 50});
8920 action.call(this); // align immediately
8924 * Clears any opacity settings from this element. Required in some cases for IE.
8925 * @return {Roo.Element} this
8927 clearOpacity : function(){
8928 if (window.ActiveXObject) {
8929 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8930 this.dom.style.filter = "";
8933 this.dom.style.opacity = "";
8934 this.dom.style["-moz-opacity"] = "";
8935 this.dom.style["-khtml-opacity"] = "";
8941 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8942 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8943 * @return {Roo.Element} this
8945 hide : function(animate){
8946 this.setVisible(false, this.preanim(arguments, 0));
8951 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8952 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8953 * @return {Roo.Element} this
8955 show : function(animate){
8956 this.setVisible(true, this.preanim(arguments, 0));
8961 * @private Test if size has a unit, otherwise appends the default
8963 addUnits : function(size){
8964 return Roo.Element.addUnits(size, this.defaultUnit);
8968 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8969 * @return {Roo.Element} this
8971 beginMeasure : function(){
8973 if(el.offsetWidth || el.offsetHeight){
8974 return this; // offsets work already
8977 var p = this.dom, b = document.body; // start with this element
8978 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8979 var pe = Roo.get(p);
8980 if(pe.getStyle('display') == 'none'){
8981 changed.push({el: p, visibility: pe.getStyle("visibility")});
8982 p.style.visibility = "hidden";
8983 p.style.display = "block";
8987 this._measureChanged = changed;
8993 * Restores displays to before beginMeasure was called
8994 * @return {Roo.Element} this
8996 endMeasure : function(){
8997 var changed = this._measureChanged;
8999 for(var i = 0, len = changed.length; i < len; i++) {
9001 r.el.style.visibility = r.visibility;
9002 r.el.style.display = "none";
9004 this._measureChanged = null;
9010 * Update the innerHTML of this element, optionally searching for and processing scripts
9011 * @param {String} html The new HTML
9012 * @param {Boolean} loadScripts (optional) true to look for and process scripts
9013 * @param {Function} callback For async script loading you can be noticed when the update completes
9014 * @return {Roo.Element} this
9016 update : function(html, loadScripts, callback){
9017 if(typeof html == "undefined"){
9020 if(loadScripts !== true){
9021 this.dom.innerHTML = html;
9022 if(typeof callback == "function"){
9030 html += '<span id="' + id + '"></span>';
9032 E.onAvailable(id, function(){
9033 var hd = document.getElementsByTagName("head")[0];
9034 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
9035 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
9036 var typeRe = /\stype=([\'\"])(.*?)\1/i;
9039 while(match = re.exec(html)){
9040 var attrs = match[1];
9041 var srcMatch = attrs ? attrs.match(srcRe) : false;
9042 if(srcMatch && srcMatch[2]){
9043 var s = document.createElement("script");
9044 s.src = srcMatch[2];
9045 var typeMatch = attrs.match(typeRe);
9046 if(typeMatch && typeMatch[2]){
9047 s.type = typeMatch[2];
9050 }else if(match[2] && match[2].length > 0){
9051 if(window.execScript) {
9052 window.execScript(match[2]);
9060 window.eval(match[2]);
9064 var el = document.getElementById(id);
9065 if(el){el.parentNode.removeChild(el);}
9066 if(typeof callback == "function"){
9070 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
9075 * Direct access to the UpdateManager update() method (takes the same parameters).
9076 * @param {String/Function} url The url for this request or a function to call to get the url
9077 * @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}
9078 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
9079 * @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.
9080 * @return {Roo.Element} this
9083 var um = this.getUpdateManager();
9084 um.update.apply(um, arguments);
9089 * Gets this element's UpdateManager
9090 * @return {Roo.UpdateManager} The UpdateManager
9092 getUpdateManager : function(){
9093 if(!this.updateManager){
9094 this.updateManager = new Roo.UpdateManager(this);
9096 return this.updateManager;
9100 * Disables text selection for this element (normalized across browsers)
9101 * @return {Roo.Element} this
9103 unselectable : function(){
9104 this.dom.unselectable = "on";
9105 this.swallowEvent("selectstart", true);
9106 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
9107 this.addClass("x-unselectable");
9112 * Calculates the x, y to center this element on the screen
9113 * @return {Array} The x, y values [x, y]
9115 getCenterXY : function(){
9116 return this.getAlignToXY(document, 'c-c');
9120 * Centers the Element in either the viewport, or another Element.
9121 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
9123 center : function(centerIn){
9124 this.alignTo(centerIn || document, 'c-c');
9129 * Tests various css rules/browsers to determine if this element uses a border box
9132 isBorderBox : function(){
9133 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
9137 * Return a box {x, y, width, height} that can be used to set another elements
9138 * size/location to match this element.
9139 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
9140 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
9141 * @return {Object} box An object in the format {x, y, width, height}
9143 getBox : function(contentBox, local){
9148 var left = parseInt(this.getStyle("left"), 10) || 0;
9149 var top = parseInt(this.getStyle("top"), 10) || 0;
9152 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
9154 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
9156 var l = this.getBorderWidth("l")+this.getPadding("l");
9157 var r = this.getBorderWidth("r")+this.getPadding("r");
9158 var t = this.getBorderWidth("t")+this.getPadding("t");
9159 var b = this.getBorderWidth("b")+this.getPadding("b");
9160 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)};
9162 bx.right = bx.x + bx.width;
9163 bx.bottom = bx.y + bx.height;
9168 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
9169 for more information about the sides.
9170 * @param {String} sides
9173 getFrameWidth : function(sides, onlyContentBox){
9174 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
9178 * 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.
9179 * @param {Object} box The box to fill {x, y, width, height}
9180 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
9181 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9182 * @return {Roo.Element} this
9184 setBox : function(box, adjust, animate){
9185 var w = box.width, h = box.height;
9186 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
9187 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
9188 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
9190 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
9195 * Forces the browser to repaint this element
9196 * @return {Roo.Element} this
9198 repaint : function(){
9200 this.addClass("x-repaint");
9201 setTimeout(function(){
9202 Roo.get(dom).removeClass("x-repaint");
9208 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
9209 * then it returns the calculated width of the sides (see getPadding)
9210 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
9211 * @return {Object/Number}
9213 getMargins : function(side){
9216 top: parseInt(this.getStyle("margin-top"), 10) || 0,
9217 left: parseInt(this.getStyle("margin-left"), 10) || 0,
9218 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
9219 right: parseInt(this.getStyle("margin-right"), 10) || 0
9222 return this.addStyles(side, El.margins);
9227 addStyles : function(sides, styles){
9229 for(var i = 0, len = sides.length; i < len; i++){
9230 v = this.getStyle(styles[sides.charAt(i)]);
9232 w = parseInt(v, 10);
9240 * Creates a proxy element of this element
9241 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
9242 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
9243 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
9244 * @return {Roo.Element} The new proxy element
9246 createProxy : function(config, renderTo, matchBox){
9248 renderTo = Roo.getDom(renderTo);
9250 renderTo = document.body;
9252 config = typeof config == "object" ?
9253 config : {tag : "div", cls: config};
9254 var proxy = Roo.DomHelper.append(renderTo, config, true);
9256 proxy.setBox(this.getBox());
9262 * Puts a mask over this element to disable user interaction. Requires core.css.
9263 * This method can only be applied to elements which accept child nodes.
9264 * @param {String} msg (optional) A message to display in the mask
9265 * @param {String} msgCls (optional) A css class to apply to the msg element
9266 * @return {Element} The mask element
9268 mask : function(msg, msgCls)
9270 if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
9271 this.setStyle("position", "relative");
9274 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
9277 this.addClass("x-masked");
9278 this._mask.setDisplayed(true);
9283 while (dom && dom.style) {
9284 if (!isNaN(parseInt(dom.style.zIndex))) {
9285 z = Math.max(z, parseInt(dom.style.zIndex));
9287 dom = dom.parentNode;
9289 // if we are masking the body - then it hides everything..
9290 if (this.dom == document.body) {
9292 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
9293 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
9296 if(typeof msg == 'string'){
9298 this._maskMsg = Roo.DomHelper.append(this.dom, {
9299 cls: "roo-el-mask-msg",
9303 cls: 'fa fa-spinner fa-spin'
9311 var mm = this._maskMsg;
9312 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
9313 if (mm.dom.lastChild) { // weird IE issue?
9314 mm.dom.lastChild.innerHTML = msg;
9316 mm.setDisplayed(true);
9318 mm.setStyle('z-index', z + 102);
9320 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
9321 this._mask.setHeight(this.getHeight());
9323 this._mask.setStyle('z-index', z + 100);
9329 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
9330 * it is cached for reuse.
9332 unmask : function(removeEl){
9334 if(removeEl === true){
9335 this._mask.remove();
9338 this._maskMsg.remove();
9339 delete this._maskMsg;
9342 this._mask.setDisplayed(false);
9344 this._maskMsg.setDisplayed(false);
9348 this.removeClass("x-masked");
9352 * Returns true if this element is masked
9355 isMasked : function(){
9356 return this._mask && this._mask.isVisible();
9360 * Creates an iframe shim for this element to keep selects and other windowed objects from
9362 * @return {Roo.Element} The new shim element
9364 createShim : function(){
9365 var el = document.createElement('iframe');
9366 el.frameBorder = 'no';
9367 el.className = 'roo-shim';
9368 if(Roo.isIE && Roo.isSecure){
9369 el.src = Roo.SSL_SECURE_URL;
9371 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9372 shim.autoBoxAdjust = false;
9377 * Removes this element from the DOM and deletes it from the cache
9379 remove : function(){
9380 if(this.dom.parentNode){
9381 this.dom.parentNode.removeChild(this.dom);
9383 delete El.cache[this.dom.id];
9387 * Sets up event handlers to add and remove a css class when the mouse is over this element
9388 * @param {String} className
9389 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9390 * mouseout events for children elements
9391 * @return {Roo.Element} this
9393 addClassOnOver : function(className, preventFlicker){
9394 this.on("mouseover", function(){
9395 Roo.fly(this, '_internal').addClass(className);
9397 var removeFn = function(e){
9398 if(preventFlicker !== true || !e.within(this, true)){
9399 Roo.fly(this, '_internal').removeClass(className);
9402 this.on("mouseout", removeFn, this.dom);
9407 * Sets up event handlers to add and remove a css class when this element has the focus
9408 * @param {String} className
9409 * @return {Roo.Element} this
9411 addClassOnFocus : function(className){
9412 this.on("focus", function(){
9413 Roo.fly(this, '_internal').addClass(className);
9415 this.on("blur", function(){
9416 Roo.fly(this, '_internal').removeClass(className);
9421 * 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)
9422 * @param {String} className
9423 * @return {Roo.Element} this
9425 addClassOnClick : function(className){
9427 this.on("mousedown", function(){
9428 Roo.fly(dom, '_internal').addClass(className);
9429 var d = Roo.get(document);
9430 var fn = function(){
9431 Roo.fly(dom, '_internal').removeClass(className);
9432 d.removeListener("mouseup", fn);
9434 d.on("mouseup", fn);
9440 * Stops the specified event from bubbling and optionally prevents the default action
9441 * @param {String} eventName
9442 * @param {Boolean} preventDefault (optional) true to prevent the default action too
9443 * @return {Roo.Element} this
9445 swallowEvent : function(eventName, preventDefault){
9446 var fn = function(e){
9447 e.stopPropagation();
9452 if(eventName instanceof Array){
9453 for(var i = 0, len = eventName.length; i < len; i++){
9454 this.on(eventName[i], fn);
9458 this.on(eventName, fn);
9465 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9468 * Sizes this element to its parent element's dimensions performing
9469 * neccessary box adjustments.
9470 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9471 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9472 * @return {Roo.Element} this
9474 fitToParent : function(monitorResize, targetParent) {
9475 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9476 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9477 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9480 var p = Roo.get(targetParent || this.dom.parentNode);
9481 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9482 if (monitorResize === true) {
9483 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9484 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9490 * Gets the next sibling, skipping text nodes
9491 * @return {HTMLElement} The next sibling or null
9493 getNextSibling : function(){
9494 var n = this.dom.nextSibling;
9495 while(n && n.nodeType != 1){
9502 * Gets the previous sibling, skipping text nodes
9503 * @return {HTMLElement} The previous sibling or null
9505 getPrevSibling : function(){
9506 var n = this.dom.previousSibling;
9507 while(n && n.nodeType != 1){
9508 n = n.previousSibling;
9515 * Appends the passed element(s) to this element
9516 * @param {String/HTMLElement/Array/Element/CompositeElement} el
9517 * @return {Roo.Element} this
9519 appendChild: function(el){
9526 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9527 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
9528 * automatically generated with the specified attributes.
9529 * @param {HTMLElement} insertBefore (optional) a child element of this element
9530 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9531 * @return {Roo.Element} The new child element
9533 createChild: function(config, insertBefore, returnDom){
9534 config = config || {tag:'div'};
9536 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9538 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
9542 * Appends this element to the passed element
9543 * @param {String/HTMLElement/Element} el The new parent element
9544 * @return {Roo.Element} this
9546 appendTo: function(el){
9547 el = Roo.getDom(el);
9548 el.appendChild(this.dom);
9553 * Inserts this element before the passed element in the DOM
9554 * @param {String/HTMLElement/Element} el The element to insert before
9555 * @return {Roo.Element} this
9557 insertBefore: function(el){
9558 el = Roo.getDom(el);
9559 el.parentNode.insertBefore(this.dom, el);
9564 * Inserts this element after the passed element in the DOM
9565 * @param {String/HTMLElement/Element} el The element to insert after
9566 * @return {Roo.Element} this
9568 insertAfter: function(el){
9569 el = Roo.getDom(el);
9570 el.parentNode.insertBefore(this.dom, el.nextSibling);
9575 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9576 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9577 * @return {Roo.Element} The new child
9579 insertFirst: function(el, returnDom){
9581 if(typeof el == 'object' && !el.nodeType){ // dh config
9582 return this.createChild(el, this.dom.firstChild, returnDom);
9584 el = Roo.getDom(el);
9585 this.dom.insertBefore(el, this.dom.firstChild);
9586 return !returnDom ? Roo.get(el) : el;
9591 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9592 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9593 * @param {String} where (optional) 'before' or 'after' defaults to before
9594 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9595 * @return {Roo.Element} the inserted Element
9597 insertSibling: function(el, where, returnDom){
9598 where = where ? where.toLowerCase() : 'before';
9600 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9602 if(typeof el == 'object' && !el.nodeType){ // dh config
9603 if(where == 'after' && !this.dom.nextSibling){
9604 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9606 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9610 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9611 where == 'before' ? this.dom : this.dom.nextSibling);
9620 * Creates and wraps this element with another element
9621 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9622 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9623 * @return {HTMLElement/Element} The newly created wrapper element
9625 wrap: function(config, returnDom){
9627 config = {tag: "div"};
9629 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9630 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9635 * Replaces the passed element with this element
9636 * @param {String/HTMLElement/Element} el The element to replace
9637 * @return {Roo.Element} this
9639 replace: function(el){
9641 this.insertBefore(el);
9647 * Inserts an html fragment into this element
9648 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9649 * @param {String} html The HTML fragment
9650 * @param {Boolean} returnEl True to return an Roo.Element
9651 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9653 insertHtml : function(where, html, returnEl){
9654 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9655 return returnEl ? Roo.get(el) : el;
9659 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9660 * @param {Object} o The object with the attributes
9661 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9662 * @return {Roo.Element} this
9664 set : function(o, useSet){
9666 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9668 if(attr == "style" || typeof o[attr] == "function") { continue; }
9670 el.className = o["cls"];
9673 el.setAttribute(attr, o[attr]);
9680 Roo.DomHelper.applyStyles(el, o.style);
9686 * Convenience method for constructing a KeyMap
9687 * @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:
9688 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9689 * @param {Function} fn The function to call
9690 * @param {Object} scope (optional) The scope of the function
9691 * @return {Roo.KeyMap} The KeyMap created
9693 addKeyListener : function(key, fn, scope){
9695 if(typeof key != "object" || key instanceof Array){
9711 return new Roo.KeyMap(this, config);
9715 * Creates a KeyMap for this element
9716 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9717 * @return {Roo.KeyMap} The KeyMap created
9719 addKeyMap : function(config){
9720 return new Roo.KeyMap(this, config);
9724 * Returns true if this element is scrollable.
9727 isScrollable : function(){
9729 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9733 * 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().
9734 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9735 * @param {Number} value The new scroll value
9736 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9737 * @return {Element} this
9740 scrollTo : function(side, value, animate){
9741 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9743 this.dom[prop] = value;
9745 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9746 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9752 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9753 * within this element's scrollable range.
9754 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9755 * @param {Number} distance How far to scroll the element in pixels
9756 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9757 * @return {Boolean} Returns true if a scroll was triggered or false if the element
9758 * was scrolled as far as it could go.
9760 scroll : function(direction, distance, animate){
9761 if(!this.isScrollable()){
9765 var l = el.scrollLeft, t = el.scrollTop;
9766 var w = el.scrollWidth, h = el.scrollHeight;
9767 var cw = el.clientWidth, ch = el.clientHeight;
9768 direction = direction.toLowerCase();
9769 var scrolled = false;
9770 var a = this.preanim(arguments, 2);
9775 var v = Math.min(l + distance, w-cw);
9776 this.scrollTo("left", v, a);
9783 var v = Math.max(l - distance, 0);
9784 this.scrollTo("left", v, a);
9792 var v = Math.max(t - distance, 0);
9793 this.scrollTo("top", v, a);
9801 var v = Math.min(t + distance, h-ch);
9802 this.scrollTo("top", v, a);
9811 * Translates the passed page coordinates into left/top css values for this element
9812 * @param {Number/Array} x The page x or an array containing [x, y]
9813 * @param {Number} y The page y
9814 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9816 translatePoints : function(x, y){
9817 if(typeof x == 'object' || x instanceof Array){
9820 var p = this.getStyle('position');
9821 var o = this.getXY();
9823 var l = parseInt(this.getStyle('left'), 10);
9824 var t = parseInt(this.getStyle('top'), 10);
9827 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9830 t = (p == "relative") ? 0 : this.dom.offsetTop;
9833 return {left: (x - o[0] + l), top: (y - o[1] + t)};
9837 * Returns the current scroll position of the element.
9838 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9840 getScroll : function(){
9841 var d = this.dom, doc = document;
9842 if(d == doc || d == doc.body){
9843 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9844 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9845 return {left: l, top: t};
9847 return {left: d.scrollLeft, top: d.scrollTop};
9852 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9853 * are convert to standard 6 digit hex color.
9854 * @param {String} attr The css attribute
9855 * @param {String} defaultValue The default value to use when a valid color isn't found
9856 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9859 getColor : function(attr, defaultValue, prefix){
9860 var v = this.getStyle(attr);
9861 if(!v || v == "transparent" || v == "inherit") {
9862 return defaultValue;
9864 var color = typeof prefix == "undefined" ? "#" : prefix;
9865 if(v.substr(0, 4) == "rgb("){
9866 var rvs = v.slice(4, v.length -1).split(",");
9867 for(var i = 0; i < 3; i++){
9868 var h = parseInt(rvs[i]).toString(16);
9875 if(v.substr(0, 1) == "#"){
9877 for(var i = 1; i < 4; i++){
9878 var c = v.charAt(i);
9881 }else if(v.length == 7){
9882 color += v.substr(1);
9886 return(color.length > 5 ? color.toLowerCase() : defaultValue);
9890 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9891 * gradient background, rounded corners and a 4-way shadow.
9892 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9893 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9894 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9895 * @return {Roo.Element} this
9897 boxWrap : function(cls){
9898 cls = cls || 'x-box';
9899 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9900 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9905 * Returns the value of a namespaced attribute from the element's underlying DOM node.
9906 * @param {String} namespace The namespace in which to look for the attribute
9907 * @param {String} name The attribute name
9908 * @return {String} The attribute value
9910 getAttributeNS : Roo.isIE ? function(ns, name){
9912 var type = typeof d[ns+":"+name];
9913 if(type != 'undefined' && type != 'unknown'){
9914 return d[ns+":"+name];
9917 } : function(ns, name){
9919 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9924 * Sets or Returns the value the dom attribute value
9925 * @param {String|Object} name The attribute name (or object to set multiple attributes)
9926 * @param {String} value (optional) The value to set the attribute to
9927 * @return {String} The attribute value
9929 attr : function(name){
9930 if (arguments.length > 1) {
9931 this.dom.setAttribute(name, arguments[1]);
9932 return arguments[1];
9934 if (typeof(name) == 'object') {
9935 for(var i in name) {
9936 this.attr(i, name[i]);
9942 if (!this.dom.hasAttribute(name)) {
9945 return this.dom.getAttribute(name);
9952 var ep = El.prototype;
9955 * Appends an event handler (Shorthand for addListener)
9956 * @param {String} eventName The type of event to append
9957 * @param {Function} fn The method the event invokes
9958 * @param {Object} scope (optional) The scope (this object) of the fn
9959 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9962 ep.on = ep.addListener;
9964 ep.mon = ep.addListener;
9967 * Removes an event handler from this element (shorthand for removeListener)
9968 * @param {String} eventName the type of event to remove
9969 * @param {Function} fn the method the event invokes
9970 * @return {Roo.Element} this
9973 ep.un = ep.removeListener;
9976 * true to automatically adjust width and height settings for box-model issues (default to true)
9978 ep.autoBoxAdjust = true;
9981 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9984 El.addUnits = function(v, defaultUnit){
9985 if(v === "" || v == "auto"){
9988 if(v === undefined){
9991 if(typeof v == "number" || !El.unitPattern.test(v)){
9992 return v + (defaultUnit || 'px');
9997 // special markup used throughout Roo when box wrapping elements
9998 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>';
10000 * Visibility mode constant - Use visibility to hide element
10006 * Visibility mode constant - Use display to hide element
10012 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
10013 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
10014 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
10026 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
10027 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
10028 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
10029 * @return {Element} The Element object
10032 El.get = function(el){
10034 if(!el){ return null; }
10035 if(typeof el == "string"){ // element id
10036 if(!(elm = document.getElementById(el))){
10039 if(ex = El.cache[el]){
10042 ex = El.cache[el] = new El(elm);
10045 }else if(el.tagName){ // dom element
10049 if(ex = El.cache[id]){
10052 ex = El.cache[id] = new El(el);
10055 }else if(el instanceof El){
10057 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
10058 // catch case where it hasn't been appended
10059 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
10062 }else if(el.isComposite){
10064 }else if(el instanceof Array){
10065 return El.select(el);
10066 }else if(el == document){
10067 // create a bogus element object representing the document object
10069 var f = function(){};
10070 f.prototype = El.prototype;
10072 docEl.dom = document;
10080 El.uncache = function(el){
10081 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
10083 delete El.cache[a[i].id || a[i]];
10089 // Garbage collection - uncache elements/purge listeners on orphaned elements
10090 // so we don't hold a reference and cause the browser to retain them
10091 El.garbageCollect = function(){
10092 if(!Roo.enableGarbageCollector){
10093 clearInterval(El.collectorThread);
10096 for(var eid in El.cache){
10097 var el = El.cache[eid], d = el.dom;
10098 // -------------------------------------------------------
10099 // Determining what is garbage:
10100 // -------------------------------------------------------
10102 // dom node is null, definitely garbage
10103 // -------------------------------------------------------
10105 // no parentNode == direct orphan, definitely garbage
10106 // -------------------------------------------------------
10107 // !d.offsetParent && !document.getElementById(eid)
10108 // display none elements have no offsetParent so we will
10109 // also try to look it up by it's id. However, check
10110 // offsetParent first so we don't do unneeded lookups.
10111 // This enables collection of elements that are not orphans
10112 // directly, but somewhere up the line they have an orphan
10114 // -------------------------------------------------------
10115 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
10116 delete El.cache[eid];
10117 if(d && Roo.enableListenerCollection){
10123 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
10127 El.Flyweight = function(dom){
10130 El.Flyweight.prototype = El.prototype;
10132 El._flyweights = {};
10134 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
10135 * the dom node can be overwritten by other code.
10136 * @param {String/HTMLElement} el The dom node or id
10137 * @param {String} named (optional) Allows for creation of named reusable flyweights to
10138 * prevent conflicts (e.g. internally Roo uses "_internal")
10140 * @return {Element} The shared Element object
10142 El.fly = function(el, named){
10143 named = named || '_global';
10144 el = Roo.getDom(el);
10148 if(!El._flyweights[named]){
10149 El._flyweights[named] = new El.Flyweight();
10151 El._flyweights[named].dom = el;
10152 return El._flyweights[named];
10156 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
10157 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
10158 * Shorthand of {@link Roo.Element#get}
10159 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
10160 * @return {Element} The Element object
10166 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
10167 * the dom node can be overwritten by other code.
10168 * Shorthand of {@link Roo.Element#fly}
10169 * @param {String/HTMLElement} el The dom node or id
10170 * @param {String} named (optional) Allows for creation of named reusable flyweights to
10171 * prevent conflicts (e.g. internally Roo uses "_internal")
10173 * @return {Element} The shared Element object
10179 // speedy lookup for elements never to box adjust
10180 var noBoxAdjust = Roo.isStrict ? {
10183 input:1, select:1, textarea:1
10185 if(Roo.isIE || Roo.isGecko){
10186 noBoxAdjust['button'] = 1;
10190 Roo.EventManager.on(window, 'unload', function(){
10192 delete El._flyweights;
10200 Roo.Element.selectorFunction = Roo.DomQuery.select;
10203 Roo.Element.select = function(selector, unique, root){
10205 if(typeof selector == "string"){
10206 els = Roo.Element.selectorFunction(selector, root);
10207 }else if(selector.length !== undefined){
10210 throw "Invalid selector";
10212 if(unique === true){
10213 return new Roo.CompositeElement(els);
10215 return new Roo.CompositeElementLite(els);
10219 * Selects elements based on the passed CSS selector to enable working on them as 1.
10220 * @param {String/Array} selector The CSS selector or an array of elements
10221 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
10222 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
10223 * @return {CompositeElementLite/CompositeElement}
10227 Roo.select = Roo.Element.select;
10244 * Ext JS Library 1.1.1
10245 * Copyright(c) 2006-2007, Ext JS, LLC.
10247 * Originally Released Under LGPL - original licence link has changed is not relivant.
10250 * <script type="text/javascript">
10255 //Notifies Element that fx methods are available
10256 Roo.enableFx = true;
10260 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
10261 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
10262 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
10263 * Element effects to work.</p><br/>
10265 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
10266 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
10267 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
10268 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
10269 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
10270 * expected results and should be done with care.</p><br/>
10272 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
10273 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
10276 ----- -----------------------------
10277 tl The top left corner
10278 t The center of the top edge
10279 tr The top right corner
10280 l The center of the left edge
10281 r The center of the right edge
10282 bl The bottom left corner
10283 b The center of the bottom edge
10284 br The bottom right corner
10286 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
10287 * below are common options that can be passed to any Fx method.</b>
10288 * @cfg {Function} callback A function called when the effect is finished
10289 * @cfg {Object} scope The scope of the effect function
10290 * @cfg {String} easing A valid Easing value for the effect
10291 * @cfg {String} afterCls A css class to apply after the effect
10292 * @cfg {Number} duration The length of time (in seconds) that the effect should last
10293 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
10294 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
10295 * effects that end with the element being visually hidden, ignored otherwise)
10296 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
10297 * a function which returns such a specification that will be applied to the Element after the effect finishes
10298 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
10299 * @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
10300 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
10304 * Slides the element into view. An anchor point can be optionally passed to set the point of
10305 * origin for the slide effect. This function automatically handles wrapping the element with
10306 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10309 // default: slide the element in from the top
10312 // custom: slide the element in from the right with a 2-second duration
10313 el.slideIn('r', { duration: 2 });
10315 // common config options shown with default values
10321 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10322 * @param {Object} options (optional) Object literal with any of the Fx config options
10323 * @return {Roo.Element} The Element
10325 slideIn : function(anchor, o){
10326 var el = this.getFxEl();
10329 el.queueFx(o, function(){
10331 anchor = anchor || "t";
10333 // fix display to visibility
10336 // restore values after effect
10337 var r = this.getFxRestore();
10338 var b = this.getBox();
10339 // fixed size for slide
10343 var wrap = this.fxWrap(r.pos, o, "hidden");
10345 var st = this.dom.style;
10346 st.visibility = "visible";
10347 st.position = "absolute";
10349 // clear out temp styles after slide and unwrap
10350 var after = function(){
10351 el.fxUnwrap(wrap, r.pos, o);
10352 st.width = r.width;
10353 st.height = r.height;
10356 // time to calc the positions
10357 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10359 switch(anchor.toLowerCase()){
10361 wrap.setSize(b.width, 0);
10362 st.left = st.bottom = "0";
10366 wrap.setSize(0, b.height);
10367 st.right = st.top = "0";
10371 wrap.setSize(0, b.height);
10372 wrap.setX(b.right);
10373 st.left = st.top = "0";
10374 a = {width: bw, points: pt};
10377 wrap.setSize(b.width, 0);
10378 wrap.setY(b.bottom);
10379 st.left = st.top = "0";
10380 a = {height: bh, points: pt};
10383 wrap.setSize(0, 0);
10384 st.right = st.bottom = "0";
10385 a = {width: bw, height: bh};
10388 wrap.setSize(0, 0);
10389 wrap.setY(b.y+b.height);
10390 st.right = st.top = "0";
10391 a = {width: bw, height: bh, points: pt};
10394 wrap.setSize(0, 0);
10395 wrap.setXY([b.right, b.bottom]);
10396 st.left = st.top = "0";
10397 a = {width: bw, height: bh, points: pt};
10400 wrap.setSize(0, 0);
10401 wrap.setX(b.x+b.width);
10402 st.left = st.bottom = "0";
10403 a = {width: bw, height: bh, points: pt};
10406 this.dom.style.visibility = "visible";
10409 arguments.callee.anim = wrap.fxanim(a,
10419 * Slides the element out of view. An anchor point can be optionally passed to set the end point
10420 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
10421 * 'hidden') but block elements will still take up space in the document. The element must be removed
10422 * from the DOM using the 'remove' config option if desired. This function automatically handles
10423 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10426 // default: slide the element out to the top
10429 // custom: slide the element out to the right with a 2-second duration
10430 el.slideOut('r', { duration: 2 });
10432 // common config options shown with default values
10440 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10441 * @param {Object} options (optional) Object literal with any of the Fx config options
10442 * @return {Roo.Element} The Element
10444 slideOut : function(anchor, o){
10445 var el = this.getFxEl();
10448 el.queueFx(o, function(){
10450 anchor = anchor || "t";
10452 // restore values after effect
10453 var r = this.getFxRestore();
10455 var b = this.getBox();
10456 // fixed size for slide
10460 var wrap = this.fxWrap(r.pos, o, "visible");
10462 var st = this.dom.style;
10463 st.visibility = "visible";
10464 st.position = "absolute";
10468 var after = function(){
10470 el.setDisplayed(false);
10475 el.fxUnwrap(wrap, r.pos, o);
10477 st.width = r.width;
10478 st.height = r.height;
10483 var a, zero = {to: 0};
10484 switch(anchor.toLowerCase()){
10486 st.left = st.bottom = "0";
10487 a = {height: zero};
10490 st.right = st.top = "0";
10494 st.left = st.top = "0";
10495 a = {width: zero, points: {to:[b.right, b.y]}};
10498 st.left = st.top = "0";
10499 a = {height: zero, points: {to:[b.x, b.bottom]}};
10502 st.right = st.bottom = "0";
10503 a = {width: zero, height: zero};
10506 st.right = st.top = "0";
10507 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10510 st.left = st.top = "0";
10511 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10514 st.left = st.bottom = "0";
10515 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10519 arguments.callee.anim = wrap.fxanim(a,
10529 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
10530 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
10531 * The element must be removed from the DOM using the 'remove' config option if desired.
10537 // common config options shown with default values
10545 * @param {Object} options (optional) Object literal with any of the Fx config options
10546 * @return {Roo.Element} The Element
10548 puff : function(o){
10549 var el = this.getFxEl();
10552 el.queueFx(o, function(){
10553 this.clearOpacity();
10556 // restore values after effect
10557 var r = this.getFxRestore();
10558 var st = this.dom.style;
10560 var after = function(){
10562 el.setDisplayed(false);
10569 el.setPositioning(r.pos);
10570 st.width = r.width;
10571 st.height = r.height;
10576 var width = this.getWidth();
10577 var height = this.getHeight();
10579 arguments.callee.anim = this.fxanim({
10580 width : {to: this.adjustWidth(width * 2)},
10581 height : {to: this.adjustHeight(height * 2)},
10582 points : {by: [-(width * .5), -(height * .5)]},
10584 fontSize: {to:200, unit: "%"}
10595 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10596 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
10597 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10603 // all config options shown with default values
10611 * @param {Object} options (optional) Object literal with any of the Fx config options
10612 * @return {Roo.Element} The Element
10614 switchOff : function(o){
10615 var el = this.getFxEl();
10618 el.queueFx(o, function(){
10619 this.clearOpacity();
10622 // restore values after effect
10623 var r = this.getFxRestore();
10624 var st = this.dom.style;
10626 var after = function(){
10628 el.setDisplayed(false);
10634 el.setPositioning(r.pos);
10635 st.width = r.width;
10636 st.height = r.height;
10641 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10642 this.clearOpacity();
10646 points:{by:[0, this.getHeight() * .5]}
10647 }, o, 'motion', 0.3, 'easeIn', after);
10648 }).defer(100, this);
10655 * Highlights the Element by setting a color (applies to the background-color by default, but can be
10656 * changed using the "attr" config option) and then fading back to the original color. If no original
10657 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10660 // default: highlight background to yellow
10663 // custom: highlight foreground text to blue for 2 seconds
10664 el.highlight("0000ff", { attr: 'color', duration: 2 });
10666 // common config options shown with default values
10667 el.highlight("ffff9c", {
10668 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10669 endColor: (current color) or "ffffff",
10674 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10675 * @param {Object} options (optional) Object literal with any of the Fx config options
10676 * @return {Roo.Element} The Element
10678 highlight : function(color, o){
10679 var el = this.getFxEl();
10682 el.queueFx(o, function(){
10683 color = color || "ffff9c";
10684 attr = o.attr || "backgroundColor";
10686 this.clearOpacity();
10689 var origColor = this.getColor(attr);
10690 var restoreColor = this.dom.style[attr];
10691 endColor = (o.endColor || origColor) || "ffffff";
10693 var after = function(){
10694 el.dom.style[attr] = restoreColor;
10699 a[attr] = {from: color, to: endColor};
10700 arguments.callee.anim = this.fxanim(a,
10710 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10713 // default: a single light blue ripple
10716 // custom: 3 red ripples lasting 3 seconds total
10717 el.frame("ff0000", 3, { duration: 3 });
10719 // common config options shown with default values
10720 el.frame("C3DAF9", 1, {
10721 duration: 1 //duration of entire animation (not each individual ripple)
10722 // Note: Easing is not configurable and will be ignored if included
10725 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10726 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10727 * @param {Object} options (optional) Object literal with any of the Fx config options
10728 * @return {Roo.Element} The Element
10730 frame : function(color, count, o){
10731 var el = this.getFxEl();
10734 el.queueFx(o, function(){
10735 color = color || "#C3DAF9";
10736 if(color.length == 6){
10737 color = "#" + color;
10739 count = count || 1;
10740 duration = o.duration || 1;
10743 var b = this.getBox();
10744 var animFn = function(){
10745 var proxy = this.createProxy({
10748 visbility:"hidden",
10749 position:"absolute",
10750 "z-index":"35000", // yee haw
10751 border:"0px solid " + color
10754 var scale = Roo.isBorderBox ? 2 : 1;
10756 top:{from:b.y, to:b.y - 20},
10757 left:{from:b.x, to:b.x - 20},
10758 borderWidth:{from:0, to:10},
10759 opacity:{from:1, to:0},
10760 height:{from:b.height, to:(b.height + (20*scale))},
10761 width:{from:b.width, to:(b.width + (20*scale))}
10762 }, duration, function(){
10766 animFn.defer((duration/2)*1000, this);
10777 * Creates a pause before any subsequent queued effects begin. If there are
10778 * no effects queued after the pause it will have no effect.
10783 * @param {Number} seconds The length of time to pause (in seconds)
10784 * @return {Roo.Element} The Element
10786 pause : function(seconds){
10787 var el = this.getFxEl();
10790 el.queueFx(o, function(){
10791 setTimeout(function(){
10793 }, seconds * 1000);
10799 * Fade an element in (from transparent to opaque). The ending opacity can be specified
10800 * using the "endOpacity" config option.
10803 // default: fade in from opacity 0 to 100%
10806 // custom: fade in from opacity 0 to 75% over 2 seconds
10807 el.fadeIn({ endOpacity: .75, duration: 2});
10809 // common config options shown with default values
10811 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10816 * @param {Object} options (optional) Object literal with any of the Fx config options
10817 * @return {Roo.Element} The Element
10819 fadeIn : function(o){
10820 var el = this.getFxEl();
10822 el.queueFx(o, function(){
10823 this.setOpacity(0);
10825 this.dom.style.visibility = 'visible';
10826 var to = o.endOpacity || 1;
10827 arguments.callee.anim = this.fxanim({opacity:{to:to}},
10828 o, null, .5, "easeOut", function(){
10830 this.clearOpacity();
10839 * Fade an element out (from opaque to transparent). The ending opacity can be specified
10840 * using the "endOpacity" config option.
10843 // default: fade out from the element's current opacity to 0
10846 // custom: fade out from the element's current opacity to 25% over 2 seconds
10847 el.fadeOut({ endOpacity: .25, duration: 2});
10849 // common config options shown with default values
10851 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10858 * @param {Object} options (optional) Object literal with any of the Fx config options
10859 * @return {Roo.Element} The Element
10861 fadeOut : function(o){
10862 var el = this.getFxEl();
10864 el.queueFx(o, function(){
10865 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10866 o, null, .5, "easeOut", function(){
10867 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10868 this.dom.style.display = "none";
10870 this.dom.style.visibility = "hidden";
10872 this.clearOpacity();
10880 * Animates the transition of an element's dimensions from a starting height/width
10881 * to an ending height/width.
10884 // change height and width to 100x100 pixels
10885 el.scale(100, 100);
10887 // common config options shown with default values. The height and width will default to
10888 // the element's existing values if passed as null.
10891 [element's height], {
10896 * @param {Number} width The new width (pass undefined to keep the original width)
10897 * @param {Number} height The new height (pass undefined to keep the original height)
10898 * @param {Object} options (optional) Object literal with any of the Fx config options
10899 * @return {Roo.Element} The Element
10901 scale : function(w, h, o){
10902 this.shift(Roo.apply({}, o, {
10910 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10911 * Any of these properties not specified in the config object will not be changed. This effect
10912 * requires that at least one new dimension, position or opacity setting must be passed in on
10913 * the config object in order for the function to have any effect.
10916 // slide the element horizontally to x position 200 while changing the height and opacity
10917 el.shift({ x: 200, height: 50, opacity: .8 });
10919 // common config options shown with default values.
10921 width: [element's width],
10922 height: [element's height],
10923 x: [element's x position],
10924 y: [element's y position],
10925 opacity: [element's opacity],
10930 * @param {Object} options Object literal with any of the Fx config options
10931 * @return {Roo.Element} The Element
10933 shift : function(o){
10934 var el = this.getFxEl();
10936 el.queueFx(o, function(){
10937 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
10938 if(w !== undefined){
10939 a.width = {to: this.adjustWidth(w)};
10941 if(h !== undefined){
10942 a.height = {to: this.adjustHeight(h)};
10944 if(x !== undefined || y !== undefined){
10946 x !== undefined ? x : this.getX(),
10947 y !== undefined ? y : this.getY()
10950 if(op !== undefined){
10951 a.opacity = {to: op};
10953 if(o.xy !== undefined){
10954 a.points = {to: o.xy};
10956 arguments.callee.anim = this.fxanim(a,
10957 o, 'motion', .35, "easeOut", function(){
10965 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
10966 * ending point of the effect.
10969 // default: slide the element downward while fading out
10972 // custom: slide the element out to the right with a 2-second duration
10973 el.ghost('r', { duration: 2 });
10975 // common config options shown with default values
10983 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10984 * @param {Object} options (optional) Object literal with any of the Fx config options
10985 * @return {Roo.Element} The Element
10987 ghost : function(anchor, o){
10988 var el = this.getFxEl();
10991 el.queueFx(o, function(){
10992 anchor = anchor || "b";
10994 // restore values after effect
10995 var r = this.getFxRestore();
10996 var w = this.getWidth(),
10997 h = this.getHeight();
10999 var st = this.dom.style;
11001 var after = function(){
11003 el.setDisplayed(false);
11009 el.setPositioning(r.pos);
11010 st.width = r.width;
11011 st.height = r.height;
11016 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
11017 switch(anchor.toLowerCase()){
11044 arguments.callee.anim = this.fxanim(a,
11054 * Ensures that all effects queued after syncFx is called on the element are
11055 * run concurrently. This is the opposite of {@link #sequenceFx}.
11056 * @return {Roo.Element} The Element
11058 syncFx : function(){
11059 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
11068 * Ensures that all effects queued after sequenceFx is called on the element are
11069 * run in sequence. This is the opposite of {@link #syncFx}.
11070 * @return {Roo.Element} The Element
11072 sequenceFx : function(){
11073 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
11075 concurrent : false,
11082 nextFx : function(){
11083 var ef = this.fxQueue[0];
11090 * Returns true if the element has any effects actively running or queued, else returns false.
11091 * @return {Boolean} True if element has active effects, else false
11093 hasActiveFx : function(){
11094 return this.fxQueue && this.fxQueue[0];
11098 * Stops any running effects and clears the element's internal effects queue if it contains
11099 * any additional effects that haven't started yet.
11100 * @return {Roo.Element} The Element
11102 stopFx : function(){
11103 if(this.hasActiveFx()){
11104 var cur = this.fxQueue[0];
11105 if(cur && cur.anim && cur.anim.isAnimated()){
11106 this.fxQueue = [cur]; // clear out others
11107 cur.anim.stop(true);
11114 beforeFx : function(o){
11115 if(this.hasActiveFx() && !o.concurrent){
11126 * Returns true if the element is currently blocking so that no other effect can be queued
11127 * until this effect is finished, else returns false if blocking is not set. This is commonly
11128 * used to ensure that an effect initiated by a user action runs to completion prior to the
11129 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
11130 * @return {Boolean} True if blocking, else false
11132 hasFxBlock : function(){
11133 var q = this.fxQueue;
11134 return q && q[0] && q[0].block;
11138 queueFx : function(o, fn){
11142 if(!this.hasFxBlock()){
11143 Roo.applyIf(o, this.fxDefaults);
11145 var run = this.beforeFx(o);
11146 fn.block = o.block;
11147 this.fxQueue.push(fn);
11159 fxWrap : function(pos, o, vis){
11161 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
11164 wrapXY = this.getXY();
11166 var div = document.createElement("div");
11167 div.style.visibility = vis;
11168 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
11169 wrap.setPositioning(pos);
11170 if(wrap.getStyle("position") == "static"){
11171 wrap.position("relative");
11173 this.clearPositioning('auto');
11175 wrap.dom.appendChild(this.dom);
11177 wrap.setXY(wrapXY);
11184 fxUnwrap : function(wrap, pos, o){
11185 this.clearPositioning();
11186 this.setPositioning(pos);
11188 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
11194 getFxRestore : function(){
11195 var st = this.dom.style;
11196 return {pos: this.getPositioning(), width: st.width, height : st.height};
11200 afterFx : function(o){
11202 this.applyStyles(o.afterStyle);
11205 this.addClass(o.afterCls);
11207 if(o.remove === true){
11210 Roo.callback(o.callback, o.scope, [this]);
11212 this.fxQueue.shift();
11218 getFxEl : function(){ // support for composite element fx
11219 return Roo.get(this.dom);
11223 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
11224 animType = animType || 'run';
11226 var anim = Roo.lib.Anim[animType](
11228 (opt.duration || defaultDur) || .35,
11229 (opt.easing || defaultEase) || 'easeOut',
11231 Roo.callback(cb, this);
11240 // backwords compat
11241 Roo.Fx.resize = Roo.Fx.scale;
11243 //When included, Roo.Fx is automatically applied to Element so that all basic
11244 //effects are available directly via the Element API
11245 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
11247 * Ext JS Library 1.1.1
11248 * Copyright(c) 2006-2007, Ext JS, LLC.
11250 * Originally Released Under LGPL - original licence link has changed is not relivant.
11253 * <script type="text/javascript">
11258 * @class Roo.CompositeElement
11259 * Standard composite class. Creates a Roo.Element for every element in the collection.
11261 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11262 * actions will be performed on all the elements in this collection.</b>
11264 * All methods return <i>this</i> and can be chained.
11266 var els = Roo.select("#some-el div.some-class", true);
11267 // or select directly from an existing element
11268 var el = Roo.get('some-el');
11269 el.select('div.some-class', true);
11271 els.setWidth(100); // all elements become 100 width
11272 els.hide(true); // all elements fade out and hide
11274 els.setWidth(100).hide(true);
11277 Roo.CompositeElement = function(els){
11278 this.elements = [];
11279 this.addElements(els);
11281 Roo.CompositeElement.prototype = {
11283 addElements : function(els){
11287 if(typeof els == "string"){
11288 els = Roo.Element.selectorFunction(els);
11290 var yels = this.elements;
11291 var index = yels.length-1;
11292 for(var i = 0, len = els.length; i < len; i++) {
11293 yels[++index] = Roo.get(els[i]);
11299 * Clears this composite and adds the elements returned by the passed selector.
11300 * @param {String/Array} els A string CSS selector, an array of elements or an element
11301 * @return {CompositeElement} this
11303 fill : function(els){
11304 this.elements = [];
11310 * Filters this composite to only elements that match the passed selector.
11311 * @param {String} selector A string CSS selector
11312 * @param {Boolean} inverse return inverse filter (not matches)
11313 * @return {CompositeElement} this
11315 filter : function(selector, inverse){
11317 inverse = inverse || false;
11318 this.each(function(el){
11319 var match = inverse ? !el.is(selector) : el.is(selector);
11321 els[els.length] = el.dom;
11328 invoke : function(fn, args){
11329 var els = this.elements;
11330 for(var i = 0, len = els.length; i < len; i++) {
11331 Roo.Element.prototype[fn].apply(els[i], args);
11336 * Adds elements to this composite.
11337 * @param {String/Array} els A string CSS selector, an array of elements or an element
11338 * @return {CompositeElement} this
11340 add : function(els){
11341 if(typeof els == "string"){
11342 this.addElements(Roo.Element.selectorFunction(els));
11343 }else if(els.length !== undefined){
11344 this.addElements(els);
11346 this.addElements([els]);
11351 * Calls the passed function passing (el, this, index) for each element in this composite.
11352 * @param {Function} fn The function to call
11353 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11354 * @return {CompositeElement} this
11356 each : function(fn, scope){
11357 var els = this.elements;
11358 for(var i = 0, len = els.length; i < len; i++){
11359 if(fn.call(scope || els[i], els[i], this, i) === false) {
11367 * Returns the Element object at the specified index
11368 * @param {Number} index
11369 * @return {Roo.Element}
11371 item : function(index){
11372 return this.elements[index] || null;
11376 * Returns the first Element
11377 * @return {Roo.Element}
11379 first : function(){
11380 return this.item(0);
11384 * Returns the last Element
11385 * @return {Roo.Element}
11388 return this.item(this.elements.length-1);
11392 * Returns the number of elements in this composite
11395 getCount : function(){
11396 return this.elements.length;
11400 * Returns true if this composite contains the passed element
11403 contains : function(el){
11404 return this.indexOf(el) !== -1;
11408 * Returns true if this composite contains the passed element
11411 indexOf : function(el){
11412 return this.elements.indexOf(Roo.get(el));
11417 * Removes the specified element(s).
11418 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11419 * or an array of any of those.
11420 * @param {Boolean} removeDom (optional) True to also remove the element from the document
11421 * @return {CompositeElement} this
11423 removeElement : function(el, removeDom){
11424 if(el instanceof Array){
11425 for(var i = 0, len = el.length; i < len; i++){
11426 this.removeElement(el[i]);
11430 var index = typeof el == 'number' ? el : this.indexOf(el);
11433 var d = this.elements[index];
11437 d.parentNode.removeChild(d);
11440 this.elements.splice(index, 1);
11446 * Replaces the specified element with the passed element.
11447 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11449 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11450 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11451 * @return {CompositeElement} this
11453 replaceElement : function(el, replacement, domReplace){
11454 var index = typeof el == 'number' ? el : this.indexOf(el);
11457 this.elements[index].replaceWith(replacement);
11459 this.elements.splice(index, 1, Roo.get(replacement))
11466 * Removes all elements.
11468 clear : function(){
11469 this.elements = [];
11473 Roo.CompositeElement.createCall = function(proto, fnName){
11474 if(!proto[fnName]){
11475 proto[fnName] = function(){
11476 return this.invoke(fnName, arguments);
11480 for(var fnName in Roo.Element.prototype){
11481 if(typeof Roo.Element.prototype[fnName] == "function"){
11482 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11488 * Ext JS Library 1.1.1
11489 * Copyright(c) 2006-2007, Ext JS, LLC.
11491 * Originally Released Under LGPL - original licence link has changed is not relivant.
11494 * <script type="text/javascript">
11498 * @class Roo.CompositeElementLite
11499 * @extends Roo.CompositeElement
11500 * Flyweight composite class. Reuses the same Roo.Element for element operations.
11502 var els = Roo.select("#some-el div.some-class");
11503 // or select directly from an existing element
11504 var el = Roo.get('some-el');
11505 el.select('div.some-class');
11507 els.setWidth(100); // all elements become 100 width
11508 els.hide(true); // all elements fade out and hide
11510 els.setWidth(100).hide(true);
11511 </code></pre><br><br>
11512 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11513 * actions will be performed on all the elements in this collection.</b>
11515 Roo.CompositeElementLite = function(els){
11516 Roo.CompositeElementLite.superclass.constructor.call(this, els);
11517 this.el = new Roo.Element.Flyweight();
11519 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11520 addElements : function(els){
11522 if(els instanceof Array){
11523 this.elements = this.elements.concat(els);
11525 var yels = this.elements;
11526 var index = yels.length-1;
11527 for(var i = 0, len = els.length; i < len; i++) {
11528 yels[++index] = els[i];
11534 invoke : function(fn, args){
11535 var els = this.elements;
11537 for(var i = 0, len = els.length; i < len; i++) {
11539 Roo.Element.prototype[fn].apply(el, args);
11544 * Returns a flyweight Element of the dom element object at the specified index
11545 * @param {Number} index
11546 * @return {Roo.Element}
11548 item : function(index){
11549 if(!this.elements[index]){
11552 this.el.dom = this.elements[index];
11556 // fixes scope with flyweight
11557 addListener : function(eventName, handler, scope, opt){
11558 var els = this.elements;
11559 for(var i = 0, len = els.length; i < len; i++) {
11560 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11566 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11567 * passed is the flyweight (shared) Roo.Element instance, so if you require a
11568 * a reference to the dom node, use el.dom.</b>
11569 * @param {Function} fn The function to call
11570 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11571 * @return {CompositeElement} this
11573 each : function(fn, scope){
11574 var els = this.elements;
11576 for(var i = 0, len = els.length; i < len; i++){
11578 if(fn.call(scope || el, el, this, i) === false){
11585 indexOf : function(el){
11586 return this.elements.indexOf(Roo.getDom(el));
11589 replaceElement : function(el, replacement, domReplace){
11590 var index = typeof el == 'number' ? el : this.indexOf(el);
11592 replacement = Roo.getDom(replacement);
11594 var d = this.elements[index];
11595 d.parentNode.insertBefore(replacement, d);
11596 d.parentNode.removeChild(d);
11598 this.elements.splice(index, 1, replacement);
11603 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11607 * Ext JS Library 1.1.1
11608 * Copyright(c) 2006-2007, Ext JS, LLC.
11610 * Originally Released Under LGPL - original licence link has changed is not relivant.
11613 * <script type="text/javascript">
11619 * @class Roo.data.Connection
11620 * @extends Roo.util.Observable
11621 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11622 * either to a configured URL, or to a URL specified at request time.
11624 * Requests made by this class are asynchronous, and will return immediately. No data from
11625 * the server will be available to the statement immediately following the {@link #request} call.
11626 * To process returned data, use a callback in the request options object, or an event listener.
11628 * Note: If you are doing a file upload, you will not get a normal response object sent back to
11629 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11630 * The response object is created using the innerHTML of the IFRAME's document as the responseText
11631 * property and, if present, the IFRAME's XML document as the responseXML property.
11633 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11634 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
11635 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11636 * standard DOM methods.
11638 * @param {Object} config a configuration object.
11640 Roo.data.Connection = function(config){
11641 Roo.apply(this, config);
11644 * @event beforerequest
11645 * Fires before a network request is made to retrieve a data object.
11646 * @param {Connection} conn This Connection object.
11647 * @param {Object} options The options config object passed to the {@link #request} method.
11649 "beforerequest" : true,
11651 * @event requestcomplete
11652 * Fires if the request was successfully completed.
11653 * @param {Connection} conn This Connection object.
11654 * @param {Object} response The XHR object containing the response data.
11655 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11656 * @param {Object} options The options config object passed to the {@link #request} method.
11658 "requestcomplete" : true,
11660 * @event requestexception
11661 * Fires if an error HTTP status was returned from the server.
11662 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11663 * @param {Connection} conn This Connection object.
11664 * @param {Object} response The XHR object containing the response data.
11665 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11666 * @param {Object} options The options config object passed to the {@link #request} method.
11668 "requestexception" : true
11670 Roo.data.Connection.superclass.constructor.call(this);
11673 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11675 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11678 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11679 * extra parameters to each request made by this object. (defaults to undefined)
11682 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11683 * to each request made by this object. (defaults to undefined)
11686 * @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)
11689 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11693 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11699 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11702 disableCaching: true,
11705 * Sends an HTTP request to a remote server.
11706 * @param {Object} options An object which may contain the following properties:<ul>
11707 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11708 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11709 * request, a url encoded string or a function to call to get either.</li>
11710 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11711 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11712 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11713 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11714 * <li>options {Object} The parameter to the request call.</li>
11715 * <li>success {Boolean} True if the request succeeded.</li>
11716 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11718 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11719 * The callback is passed the following parameters:<ul>
11720 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11721 * <li>options {Object} The parameter to the request call.</li>
11723 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11724 * The callback is passed the following parameters:<ul>
11725 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11726 * <li>options {Object} The parameter to the request call.</li>
11728 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11729 * for the callback function. Defaults to the browser window.</li>
11730 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11731 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11732 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11733 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11734 * params for the post data. Any params will be appended to the URL.</li>
11735 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11737 * @return {Number} transactionId
11739 request : function(o){
11740 if(this.fireEvent("beforerequest", this, o) !== false){
11743 if(typeof p == "function"){
11744 p = p.call(o.scope||window, o);
11746 if(typeof p == "object"){
11747 p = Roo.urlEncode(o.params);
11749 if(this.extraParams){
11750 var extras = Roo.urlEncode(this.extraParams);
11751 p = p ? (p + '&' + extras) : extras;
11754 var url = o.url || this.url;
11755 if(typeof url == 'function'){
11756 url = url.call(o.scope||window, o);
11760 var form = Roo.getDom(o.form);
11761 url = url || form.action;
11763 var enctype = form.getAttribute("enctype");
11766 return this.doFormDataUpload(o, url);
11769 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11770 return this.doFormUpload(o, p, url);
11772 var f = Roo.lib.Ajax.serializeForm(form);
11773 p = p ? (p + '&' + f) : f;
11776 if (!o.form && o.formData) {
11777 o.formData = o.formData === true ? new FormData() : o.formData;
11778 for (var k in o.params) {
11779 o.formData.append(k,o.params[k]);
11782 return this.doFormDataUpload(o, url);
11786 var hs = o.headers;
11787 if(this.defaultHeaders){
11788 hs = Roo.apply(hs || {}, this.defaultHeaders);
11795 success: this.handleResponse,
11796 failure: this.handleFailure,
11798 argument: {options: o},
11799 timeout : o.timeout || this.timeout
11802 var method = o.method||this.method||(p ? "POST" : "GET");
11804 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11805 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11808 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11812 }else if(this.autoAbort !== false){
11816 if((method == 'GET' && p) || o.xmlData){
11817 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11820 Roo.lib.Ajax.useDefaultHeader = typeof(o.headers) == 'undefined' || typeof(o.headers['Content-Type']) == 'undefined';
11821 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11822 Roo.lib.Ajax.useDefaultHeader == true;
11823 return this.transId;
11825 Roo.callback(o.callback, o.scope, [o, null, null]);
11831 * Determine whether this object has a request outstanding.
11832 * @param {Number} transactionId (Optional) defaults to the last transaction
11833 * @return {Boolean} True if there is an outstanding request.
11835 isLoading : function(transId){
11837 return Roo.lib.Ajax.isCallInProgress(transId);
11839 return this.transId ? true : false;
11844 * Aborts any outstanding request.
11845 * @param {Number} transactionId (Optional) defaults to the last transaction
11847 abort : function(transId){
11848 if(transId || this.isLoading()){
11849 Roo.lib.Ajax.abort(transId || this.transId);
11854 handleResponse : function(response){
11855 this.transId = false;
11856 var options = response.argument.options;
11857 response.argument = options ? options.argument : null;
11858 this.fireEvent("requestcomplete", this, response, options);
11859 Roo.callback(options.success, options.scope, [response, options]);
11860 Roo.callback(options.callback, options.scope, [options, true, response]);
11864 handleFailure : function(response, e){
11865 this.transId = false;
11866 var options = response.argument.options;
11867 response.argument = options ? options.argument : null;
11868 this.fireEvent("requestexception", this, response, options, e);
11869 Roo.callback(options.failure, options.scope, [response, options]);
11870 Roo.callback(options.callback, options.scope, [options, false, response]);
11874 doFormUpload : function(o, ps, url){
11876 var frame = document.createElement('iframe');
11879 frame.className = 'x-hidden';
11881 frame.src = Roo.SSL_SECURE_URL;
11883 document.body.appendChild(frame);
11886 document.frames[id].name = id;
11889 var form = Roo.getDom(o.form);
11891 form.method = 'POST';
11892 form.enctype = form.encoding = 'multipart/form-data';
11898 if(ps){ // add dynamic params
11900 ps = Roo.urlDecode(ps, false);
11902 if(ps.hasOwnProperty(k)){
11903 hd = document.createElement('input');
11904 hd.type = 'hidden';
11907 form.appendChild(hd);
11914 var r = { // bogus response object
11919 r.argument = o ? o.argument : null;
11924 doc = frame.contentWindow.document;
11926 doc = (frame.contentDocument || window.frames[id].document);
11928 if(doc && doc.body){
11929 r.responseText = doc.body.innerHTML;
11931 if(doc && doc.XMLDocument){
11932 r.responseXML = doc.XMLDocument;
11934 r.responseXML = doc;
11941 Roo.EventManager.removeListener(frame, 'load', cb, this);
11943 this.fireEvent("requestcomplete", this, r, o);
11944 Roo.callback(o.success, o.scope, [r, o]);
11945 Roo.callback(o.callback, o.scope, [o, true, r]);
11947 setTimeout(function(){document.body.removeChild(frame);}, 100);
11950 Roo.EventManager.on(frame, 'load', cb, this);
11953 if(hiddens){ // remove dynamic params
11954 for(var i = 0, len = hiddens.length; i < len; i++){
11955 form.removeChild(hiddens[i]);
11959 // this is a 'formdata version???'
11962 doFormDataUpload : function(o, url)
11966 var form = Roo.getDom(o.form);
11967 form.enctype = form.encoding = 'multipart/form-data';
11968 formData = o.formData === true ? new FormData(form) : o.formData;
11970 formData = o.formData === true ? new FormData() : o.formData;
11975 success: this.handleResponse,
11976 failure: this.handleFailure,
11978 argument: {options: o},
11979 timeout : o.timeout || this.timeout
11982 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11986 }else if(this.autoAbort !== false){
11990 //Roo.lib.Ajax.defaultPostHeader = null;
11991 Roo.lib.Ajax.useDefaultHeader = false;
11992 this.transId = Roo.lib.Ajax.request( "POST", url, cb, formData, o);
11993 Roo.lib.Ajax.useDefaultHeader = true;
12001 * Ext JS Library 1.1.1
12002 * Copyright(c) 2006-2007, Ext JS, LLC.
12004 * Originally Released Under LGPL - original licence link has changed is not relivant.
12007 * <script type="text/javascript">
12011 * Global Ajax request class.
12014 * @extends Roo.data.Connection
12017 * @cfg {String} url The default URL to be used for requests to the server. (defaults to undefined)
12018 * @cfg {Object} extraParams An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
12019 * @cfg {Object} defaultHeaders An object containing request headers which are added to each request made by this object. (defaults to undefined)
12020 * @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)
12021 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
12022 * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
12023 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
12025 Roo.Ajax = new Roo.data.Connection({
12034 * Serialize the passed form into a url encoded string
12036 * @param {String/HTMLElement} form
12039 serializeForm : function(form){
12040 return Roo.lib.Ajax.serializeForm(form);
12044 * Ext JS Library 1.1.1
12045 * Copyright(c) 2006-2007, Ext JS, LLC.
12047 * Originally Released Under LGPL - original licence link has changed is not relivant.
12050 * <script type="text/javascript">
12055 * @class Roo.UpdateManager
12056 * @extends Roo.util.Observable
12057 * Provides AJAX-style update for Element object.<br><br>
12060 * // Get it from a Roo.Element object
12061 * var el = Roo.get("foo");
12062 * var mgr = el.getUpdateManager();
12063 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
12065 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
12067 * // or directly (returns the same UpdateManager instance)
12068 * var mgr = new Roo.UpdateManager("myElementId");
12069 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
12070 * mgr.on("update", myFcnNeedsToKnow);
12072 // short handed call directly from the element object
12073 Roo.get("foo").load({
12077 text: "Loading Foo..."
12081 * Create new UpdateManager directly.
12082 * @param {String/HTMLElement/Roo.Element} el The element to update
12083 * @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).
12085 Roo.UpdateManager = function(el, forceNew){
12087 if(!forceNew && el.updateManager){
12088 return el.updateManager;
12091 * The Element object
12092 * @type Roo.Element
12096 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
12099 this.defaultUrl = null;
12103 * @event beforeupdate
12104 * Fired before an update is made, return false from your handler and the update is cancelled.
12105 * @param {Roo.Element} el
12106 * @param {String/Object/Function} url
12107 * @param {String/Object} params
12109 "beforeupdate": true,
12112 * Fired after successful update is made.
12113 * @param {Roo.Element} el
12114 * @param {Object} oResponseObject The response Object
12119 * Fired on update failure.
12120 * @param {Roo.Element} el
12121 * @param {Object} oResponseObject The response Object
12125 var d = Roo.UpdateManager.defaults;
12127 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
12130 this.sslBlankUrl = d.sslBlankUrl;
12132 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
12135 this.disableCaching = d.disableCaching;
12137 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
12140 this.indicatorText = d.indicatorText;
12142 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
12145 this.showLoadIndicator = d.showLoadIndicator;
12147 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
12150 this.timeout = d.timeout;
12153 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
12156 this.loadScripts = d.loadScripts;
12159 * Transaction object of current executing transaction
12161 this.transaction = null;
12166 this.autoRefreshProcId = null;
12168 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
12171 this.refreshDelegate = this.refresh.createDelegate(this);
12173 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
12176 this.updateDelegate = this.update.createDelegate(this);
12178 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
12181 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
12185 this.successDelegate = this.processSuccess.createDelegate(this);
12189 this.failureDelegate = this.processFailure.createDelegate(this);
12191 if(!this.renderer){
12193 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
12195 this.renderer = new Roo.UpdateManager.BasicRenderer();
12198 Roo.UpdateManager.superclass.constructor.call(this);
12201 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
12203 * Get the Element this UpdateManager is bound to
12204 * @return {Roo.Element} The element
12206 getEl : function(){
12210 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
12211 * @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:
12214 url: "your-url.php",<br/>
12215 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
12216 callback: yourFunction,<br/>
12217 scope: yourObject, //(optional scope) <br/>
12218 discardUrl: false, <br/>
12219 nocache: false,<br/>
12220 text: "Loading...",<br/>
12222 scripts: false<br/>
12225 * The only required property is url. The optional properties nocache, text and scripts
12226 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
12227 * @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}
12228 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
12229 * @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.
12231 update : function(url, params, callback, discardUrl){
12232 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
12233 var method = this.method,
12235 if(typeof url == "object"){ // must be config object
12238 params = params || cfg.params;
12239 callback = callback || cfg.callback;
12240 discardUrl = discardUrl || cfg.discardUrl;
12241 if(callback && cfg.scope){
12242 callback = callback.createDelegate(cfg.scope);
12244 if(typeof cfg.method != "undefined"){method = cfg.method;};
12245 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
12246 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
12247 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
12248 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
12250 this.showLoading();
12252 this.defaultUrl = url;
12254 if(typeof url == "function"){
12255 url = url.call(this);
12258 method = method || (params ? "POST" : "GET");
12259 if(method == "GET"){
12260 url = this.prepareUrl(url);
12263 var o = Roo.apply(cfg ||{}, {
12266 success: this.successDelegate,
12267 failure: this.failureDelegate,
12268 callback: undefined,
12269 timeout: (this.timeout*1000),
12270 argument: {"url": url, "form": null, "callback": callback, "params": params}
12272 Roo.log("updated manager called with timeout of " + o.timeout);
12273 this.transaction = Roo.Ajax.request(o);
12278 * 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.
12279 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
12280 * @param {String/HTMLElement} form The form Id or form element
12281 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
12282 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
12283 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
12285 formUpdate : function(form, url, reset, callback){
12286 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
12287 if(typeof url == "function"){
12288 url = url.call(this);
12290 form = Roo.getDom(form);
12291 this.transaction = Roo.Ajax.request({
12294 success: this.successDelegate,
12295 failure: this.failureDelegate,
12296 timeout: (this.timeout*1000),
12297 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
12299 this.showLoading.defer(1, this);
12304 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
12305 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12307 refresh : function(callback){
12308 if(this.defaultUrl == null){
12311 this.update(this.defaultUrl, null, callback, true);
12315 * Set this element to auto refresh.
12316 * @param {Number} interval How often to update (in seconds).
12317 * @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)
12318 * @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}
12319 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12320 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
12322 startAutoRefresh : function(interval, url, params, callback, refreshNow){
12324 this.update(url || this.defaultUrl, params, callback, true);
12326 if(this.autoRefreshProcId){
12327 clearInterval(this.autoRefreshProcId);
12329 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
12333 * Stop auto refresh on this element.
12335 stopAutoRefresh : function(){
12336 if(this.autoRefreshProcId){
12337 clearInterval(this.autoRefreshProcId);
12338 delete this.autoRefreshProcId;
12342 isAutoRefreshing : function(){
12343 return this.autoRefreshProcId ? true : false;
12346 * Called to update the element to "Loading" state. Override to perform custom action.
12348 showLoading : function(){
12349 if(this.showLoadIndicator){
12350 this.el.update(this.indicatorText);
12355 * Adds unique parameter to query string if disableCaching = true
12358 prepareUrl : function(url){
12359 if(this.disableCaching){
12360 var append = "_dc=" + (new Date().getTime());
12361 if(url.indexOf("?") !== -1){
12362 url += "&" + append;
12364 url += "?" + append;
12373 processSuccess : function(response){
12374 this.transaction = null;
12375 if(response.argument.form && response.argument.reset){
12376 try{ // put in try/catch since some older FF releases had problems with this
12377 response.argument.form.reset();
12380 if(this.loadScripts){
12381 this.renderer.render(this.el, response, this,
12382 this.updateComplete.createDelegate(this, [response]));
12384 this.renderer.render(this.el, response, this);
12385 this.updateComplete(response);
12389 updateComplete : function(response){
12390 this.fireEvent("update", this.el, response);
12391 if(typeof response.argument.callback == "function"){
12392 response.argument.callback(this.el, true, response);
12399 processFailure : function(response){
12400 this.transaction = null;
12401 this.fireEvent("failure", this.el, response);
12402 if(typeof response.argument.callback == "function"){
12403 response.argument.callback(this.el, false, response);
12408 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12409 * @param {Object} renderer The object implementing the render() method
12411 setRenderer : function(renderer){
12412 this.renderer = renderer;
12415 getRenderer : function(){
12416 return this.renderer;
12420 * Set the defaultUrl used for updates
12421 * @param {String/Function} defaultUrl The url or a function to call to get the url
12423 setDefaultUrl : function(defaultUrl){
12424 this.defaultUrl = defaultUrl;
12428 * Aborts the executing transaction
12430 abort : function(){
12431 if(this.transaction){
12432 Roo.Ajax.abort(this.transaction);
12437 * Returns true if an update is in progress
12438 * @return {Boolean}
12440 isUpdating : function(){
12441 if(this.transaction){
12442 return Roo.Ajax.isLoading(this.transaction);
12449 * @class Roo.UpdateManager.defaults
12450 * @static (not really - but it helps the doc tool)
12451 * The defaults collection enables customizing the default properties of UpdateManager
12453 Roo.UpdateManager.defaults = {
12455 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12461 * True to process scripts by default (Defaults to false).
12464 loadScripts : false,
12467 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12470 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12472 * Whether to append unique parameter on get request to disable caching (Defaults to false).
12475 disableCaching : false,
12477 * Whether to show indicatorText when loading (Defaults to true).
12480 showLoadIndicator : true,
12482 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
12485 indicatorText : '<div class="loading-indicator">Loading...</div>'
12489 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12491 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12492 * @param {String/HTMLElement/Roo.Element} el The element to update
12493 * @param {String} url The url
12494 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12495 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12498 * @member Roo.UpdateManager
12500 Roo.UpdateManager.updateElement = function(el, url, params, options){
12501 var um = Roo.get(el, true).getUpdateManager();
12502 Roo.apply(um, options);
12503 um.update(url, params, options ? options.callback : null);
12505 // alias for backwards compat
12506 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12508 * @class Roo.UpdateManager.BasicRenderer
12509 * Default Content renderer. Updates the elements innerHTML with the responseText.
12511 Roo.UpdateManager.BasicRenderer = function(){};
12513 Roo.UpdateManager.BasicRenderer.prototype = {
12515 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12516 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12517 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12518 * @param {Roo.Element} el The element being rendered
12519 * @param {Object} response The YUI Connect response object
12520 * @param {UpdateManager} updateManager The calling update manager
12521 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12523 render : function(el, response, updateManager, callback){
12524 el.update(response.responseText, updateManager.loadScripts, callback);
12530 * (c)) Alan Knowles
12536 * @class Roo.DomTemplate
12537 * @extends Roo.Template
12538 * An effort at a dom based template engine..
12540 * Similar to XTemplate, except it uses dom parsing to create the template..
12542 * Supported features:
12547 {a_variable} - output encoded.
12548 {a_variable.format:("Y-m-d")} - call a method on the variable
12549 {a_variable:raw} - unencoded output
12550 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12551 {a_variable:this.method_on_template(...)} - call a method on the template object.
12556 <div roo-for="a_variable or condition.."></div>
12557 <div roo-if="a_variable or condition"></div>
12558 <div roo-exec="some javascript"></div>
12559 <div roo-name="named_template"></div>
12564 Roo.DomTemplate = function()
12566 Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12573 Roo.extend(Roo.DomTemplate, Roo.Template, {
12575 * id counter for sub templates.
12579 * flag to indicate if dom parser is inside a pre,
12580 * it will strip whitespace if not.
12585 * The various sub templates
12593 * basic tag replacing syntax
12596 * // you can fake an object call by doing this
12600 re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12601 //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12603 iterChild : function (node, method) {
12605 var oldPre = this.inPre;
12606 if (node.tagName == 'PRE') {
12609 for( var i = 0; i < node.childNodes.length; i++) {
12610 method.call(this, node.childNodes[i]);
12612 this.inPre = oldPre;
12618 * compile the template
12620 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12623 compile: function()
12627 // covert the html into DOM...
12631 doc = document.implementation.createHTMLDocument("");
12632 doc.documentElement.innerHTML = this.html ;
12633 div = doc.documentElement;
12635 // old IE... - nasty -- it causes all sorts of issues.. with
12636 // images getting pulled from server..
12637 div = document.createElement('div');
12638 div.innerHTML = this.html;
12640 //doc.documentElement.innerHTML = htmlBody
12646 this.iterChild(div, function(n) {_t.compileNode(n, true); });
12648 var tpls = this.tpls;
12650 // create a top level template from the snippet..
12652 //Roo.log(div.innerHTML);
12659 body : div.innerHTML,
12672 Roo.each(tpls, function(tp){
12673 this.compileTpl(tp);
12674 this.tpls[tp.id] = tp;
12677 this.master = tpls[0];
12683 compileNode : function(node, istop) {
12688 // skip anything not a tag..
12689 if (node.nodeType != 1) {
12690 if (node.nodeType == 3 && !this.inPre) {
12691 // reduce white space..
12692 node.nodeValue = node.nodeValue.replace(/\s+/g, ' ');
12715 case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12716 case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12717 case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12718 case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12724 // just itterate children..
12725 this.iterChild(node,this.compileNode);
12728 tpl.uid = this.id++;
12729 tpl.value = node.getAttribute('roo-' + tpl.attr);
12730 node.removeAttribute('roo-'+ tpl.attr);
12731 if (tpl.attr != 'name') {
12732 var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12733 node.parentNode.replaceChild(placeholder, node);
12736 var placeholder = document.createElement('span');
12737 placeholder.className = 'roo-tpl-' + tpl.value;
12738 node.parentNode.replaceChild(placeholder, node);
12741 // parent now sees '{domtplXXXX}
12742 this.iterChild(node,this.compileNode);
12744 // we should now have node body...
12745 var div = document.createElement('div');
12746 div.appendChild(node);
12748 // this has the unfortunate side effect of converting tagged attributes
12749 // eg. href="{...}" into %7C...%7D
12750 // this has been fixed by searching for those combo's although it's a bit hacky..
12753 tpl.body = div.innerHTML;
12760 switch (tpl.value) {
12761 case '.': tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12762 case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12763 default: tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12768 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12772 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12776 tpl.id = tpl.value; // replace non characters???
12782 this.tpls.push(tpl);
12792 * Compile a segment of the template into a 'sub-template'
12798 compileTpl : function(tpl)
12800 var fm = Roo.util.Format;
12801 var useF = this.disableFormats !== true;
12803 var sep = Roo.isGecko ? "+\n" : ",\n";
12805 var undef = function(str) {
12806 Roo.debug && Roo.log("Property not found :" + str);
12810 //Roo.log(tpl.body);
12814 var fn = function(m, lbrace, name, format, args)
12817 //Roo.log(arguments);
12818 args = args ? args.replace(/\\'/g,"'") : args;
12819 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12820 if (typeof(format) == 'undefined') {
12821 format = 'htmlEncode';
12823 if (format == 'raw' ) {
12827 if(name.substr(0, 6) == 'domtpl'){
12828 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12831 // build an array of options to determine if value is undefined..
12833 // basically get 'xxxx.yyyy' then do
12834 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12835 // (function () { Roo.log("Property not found"); return ''; })() :
12840 Roo.each(name.split('.'), function(st) {
12841 lookfor += (lookfor.length ? '.': '') + st;
12842 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
12845 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12848 if(format && useF){
12850 args = args ? ',' + args : "";
12852 if(format.substr(0, 5) != "this."){
12853 format = "fm." + format + '(';
12855 format = 'this.call("'+ format.substr(5) + '", ';
12859 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
12862 if (args && args.length) {
12863 // called with xxyx.yuu:(test,test)
12865 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
12867 // raw.. - :raw modifier..
12868 return "'"+ sep + udef_st + name + ")"+sep+"'";
12872 // branched to use + in gecko and [].join() in others
12874 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
12875 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12878 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
12879 body.push(tpl.body.replace(/(\r\n|\n)/g,
12880 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12881 body.push("'].join('');};};");
12882 body = body.join('');
12885 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12887 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
12894 * same as applyTemplate, except it's done to one of the subTemplates
12895 * when using named templates, you can do:
12897 * var str = pl.applySubTemplate('your-name', values);
12900 * @param {Number} id of the template
12901 * @param {Object} values to apply to template
12902 * @param {Object} parent (normaly the instance of this object)
12904 applySubTemplate : function(id, values, parent)
12908 var t = this.tpls[id];
12912 if(t.ifCall && !t.ifCall.call(this, values, parent)){
12913 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12917 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12924 if(t.execCall && t.execCall.call(this, values, parent)){
12928 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12934 var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12935 parent = t.target ? values : parent;
12936 if(t.forCall && vs instanceof Array){
12938 for(var i = 0, len = vs.length; i < len; i++){
12940 buf[buf.length] = t.compiled.call(this, vs[i], parent);
12942 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12944 //Roo.log(t.compiled);
12948 return buf.join('');
12951 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12956 return t.compiled.call(this, vs, parent);
12958 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12960 //Roo.log(t.compiled);
12968 applyTemplate : function(values){
12969 return this.master.compiled.call(this, values, {});
12970 //var s = this.subs;
12973 apply : function(){
12974 return this.applyTemplate.apply(this, arguments);
12979 Roo.DomTemplate.from = function(el){
12980 el = Roo.getDom(el);
12981 return new Roo.Domtemplate(el.value || el.innerHTML);
12984 * Ext JS Library 1.1.1
12985 * Copyright(c) 2006-2007, Ext JS, LLC.
12987 * Originally Released Under LGPL - original licence link has changed is not relivant.
12990 * <script type="text/javascript">
12994 * @class Roo.util.DelayedTask
12995 * Provides a convenient method of performing setTimeout where a new
12996 * timeout cancels the old timeout. An example would be performing validation on a keypress.
12997 * You can use this class to buffer
12998 * the keypress events for a certain number of milliseconds, and perform only if they stop
12999 * for that amount of time.
13000 * @constructor The parameters to this constructor serve as defaults and are not required.
13001 * @param {Function} fn (optional) The default function to timeout
13002 * @param {Object} scope (optional) The default scope of that timeout
13003 * @param {Array} args (optional) The default Array of arguments
13005 Roo.util.DelayedTask = function(fn, scope, args){
13006 var id = null, d, t;
13008 var call = function(){
13009 var now = new Date().getTime();
13013 fn.apply(scope, args || []);
13017 * Cancels any pending timeout and queues a new one
13018 * @param {Number} delay The milliseconds to delay
13019 * @param {Function} newFn (optional) Overrides function passed to constructor
13020 * @param {Object} newScope (optional) Overrides scope passed to constructor
13021 * @param {Array} newArgs (optional) Overrides args passed to constructor
13023 this.delay = function(delay, newFn, newScope, newArgs){
13024 if(id && delay != d){
13028 t = new Date().getTime();
13030 scope = newScope || scope;
13031 args = newArgs || args;
13033 id = setInterval(call, d);
13038 * Cancel the last queued timeout
13040 this.cancel = function(){
13048 * Ext JS Library 1.1.1
13049 * Copyright(c) 2006-2007, Ext JS, LLC.
13051 * Originally Released Under LGPL - original licence link has changed is not relivant.
13054 * <script type="text/javascript">
13058 Roo.util.TaskRunner = function(interval){
13059 interval = interval || 10;
13060 var tasks = [], removeQueue = [];
13062 var running = false;
13064 var stopThread = function(){
13070 var startThread = function(){
13073 id = setInterval(runTasks, interval);
13077 var removeTask = function(task){
13078 removeQueue.push(task);
13084 var runTasks = function(){
13085 if(removeQueue.length > 0){
13086 for(var i = 0, len = removeQueue.length; i < len; i++){
13087 tasks.remove(removeQueue[i]);
13090 if(tasks.length < 1){
13095 var now = new Date().getTime();
13096 for(var i = 0, len = tasks.length; i < len; ++i){
13098 var itime = now - t.taskRunTime;
13099 if(t.interval <= itime){
13100 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
13101 t.taskRunTime = now;
13102 if(rt === false || t.taskRunCount === t.repeat){
13107 if(t.duration && t.duration <= (now - t.taskStartTime)){
13114 * Queues a new task.
13115 * @param {Object} task
13117 this.start = function(task){
13119 task.taskStartTime = new Date().getTime();
13120 task.taskRunTime = 0;
13121 task.taskRunCount = 0;
13126 this.stop = function(task){
13131 this.stopAll = function(){
13133 for(var i = 0, len = tasks.length; i < len; i++){
13134 if(tasks[i].onStop){
13143 Roo.TaskMgr = new Roo.util.TaskRunner();/*
13145 * Ext JS Library 1.1.1
13146 * Copyright(c) 2006-2007, Ext JS, LLC.
13148 * Originally Released Under LGPL - original licence link has changed is not relivant.
13151 * <script type="text/javascript">
13156 * @class Roo.util.MixedCollection
13157 * @extends Roo.util.Observable
13158 * A Collection class that maintains both numeric indexes and keys and exposes events.
13160 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
13161 * collection (defaults to false)
13162 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
13163 * and return the key value for that item. This is used when available to look up the key on items that
13164 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
13165 * equivalent to providing an implementation for the {@link #getKey} method.
13167 Roo.util.MixedCollection = function(allowFunctions, keyFn){
13175 * Fires when the collection is cleared.
13180 * Fires when an item is added to the collection.
13181 * @param {Number} index The index at which the item was added.
13182 * @param {Object} o The item added.
13183 * @param {String} key The key associated with the added item.
13188 * Fires when an item is replaced in the collection.
13189 * @param {String} key he key associated with the new added.
13190 * @param {Object} old The item being replaced.
13191 * @param {Object} new The new item.
13196 * Fires when an item is removed from the collection.
13197 * @param {Object} o The item being removed.
13198 * @param {String} key (optional) The key associated with the removed item.
13203 this.allowFunctions = allowFunctions === true;
13205 this.getKey = keyFn;
13207 Roo.util.MixedCollection.superclass.constructor.call(this);
13210 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
13211 allowFunctions : false,
13214 * Adds an item to the collection.
13215 * @param {String} key The key to associate with the item
13216 * @param {Object} o The item to add.
13217 * @return {Object} The item added.
13219 add : function(key, o){
13220 if(arguments.length == 1){
13222 key = this.getKey(o);
13224 if(typeof key == "undefined" || key === null){
13226 this.items.push(o);
13227 this.keys.push(null);
13229 var old = this.map[key];
13231 return this.replace(key, o);
13234 this.items.push(o);
13236 this.keys.push(key);
13238 this.fireEvent("add", this.length-1, o, key);
13243 * MixedCollection has a generic way to fetch keys if you implement getKey.
13246 var mc = new Roo.util.MixedCollection();
13247 mc.add(someEl.dom.id, someEl);
13248 mc.add(otherEl.dom.id, otherEl);
13252 var mc = new Roo.util.MixedCollection();
13253 mc.getKey = function(el){
13259 // or via the constructor
13260 var mc = new Roo.util.MixedCollection(false, function(el){
13266 * @param o {Object} The item for which to find the key.
13267 * @return {Object} The key for the passed item.
13269 getKey : function(o){
13274 * Replaces an item in the collection.
13275 * @param {String} key The key associated with the item to replace, or the item to replace.
13276 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
13277 * @return {Object} The new item.
13279 replace : function(key, o){
13280 if(arguments.length == 1){
13282 key = this.getKey(o);
13284 var old = this.item(key);
13285 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
13286 return this.add(key, o);
13288 var index = this.indexOfKey(key);
13289 this.items[index] = o;
13291 this.fireEvent("replace", key, old, o);
13296 * Adds all elements of an Array or an Object to the collection.
13297 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
13298 * an Array of values, each of which are added to the collection.
13300 addAll : function(objs){
13301 if(arguments.length > 1 || objs instanceof Array){
13302 var args = arguments.length > 1 ? arguments : objs;
13303 for(var i = 0, len = args.length; i < len; i++){
13307 for(var key in objs){
13308 if(this.allowFunctions || typeof objs[key] != "function"){
13309 this.add(key, objs[key]);
13316 * Executes the specified function once for every item in the collection, passing each
13317 * item as the first and only parameter. returning false from the function will stop the iteration.
13318 * @param {Function} fn The function to execute for each item.
13319 * @param {Object} scope (optional) The scope in which to execute the function.
13321 each : function(fn, scope){
13322 var items = [].concat(this.items); // each safe for removal
13323 for(var i = 0, len = items.length; i < len; i++){
13324 if(fn.call(scope || items[i], items[i], i, len) === false){
13331 * Executes the specified function once for every key in the collection, passing each
13332 * key, and its associated item as the first two parameters.
13333 * @param {Function} fn The function to execute for each item.
13334 * @param {Object} scope (optional) The scope in which to execute the function.
13336 eachKey : function(fn, scope){
13337 for(var i = 0, len = this.keys.length; i < len; i++){
13338 fn.call(scope || window, this.keys[i], this.items[i], i, len);
13343 * Returns the first item in the collection which elicits a true return value from the
13344 * passed selection function.
13345 * @param {Function} fn The selection function to execute for each item.
13346 * @param {Object} scope (optional) The scope in which to execute the function.
13347 * @return {Object} The first item in the collection which returned true from the selection function.
13349 find : function(fn, scope){
13350 for(var i = 0, len = this.items.length; i < len; i++){
13351 if(fn.call(scope || window, this.items[i], this.keys[i])){
13352 return this.items[i];
13359 * Inserts an item at the specified index in the collection.
13360 * @param {Number} index The index to insert the item at.
13361 * @param {String} key The key to associate with the new item, or the item itself.
13362 * @param {Object} o (optional) If the second parameter was a key, the new item.
13363 * @return {Object} The item inserted.
13365 insert : function(index, key, o){
13366 if(arguments.length == 2){
13368 key = this.getKey(o);
13370 if(index >= this.length){
13371 return this.add(key, o);
13374 this.items.splice(index, 0, o);
13375 if(typeof key != "undefined" && key != null){
13378 this.keys.splice(index, 0, key);
13379 this.fireEvent("add", index, o, key);
13384 * Removed an item from the collection.
13385 * @param {Object} o The item to remove.
13386 * @return {Object} The item removed.
13388 remove : function(o){
13389 return this.removeAt(this.indexOf(o));
13393 * Remove an item from a specified index in the collection.
13394 * @param {Number} index The index within the collection of the item to remove.
13396 removeAt : function(index){
13397 if(index < this.length && index >= 0){
13399 var o = this.items[index];
13400 this.items.splice(index, 1);
13401 var key = this.keys[index];
13402 if(typeof key != "undefined"){
13403 delete this.map[key];
13405 this.keys.splice(index, 1);
13406 this.fireEvent("remove", o, key);
13411 * Removed an item associated with the passed key fom the collection.
13412 * @param {String} key The key of the item to remove.
13414 removeKey : function(key){
13415 return this.removeAt(this.indexOfKey(key));
13419 * Returns the number of items in the collection.
13420 * @return {Number} the number of items in the collection.
13422 getCount : function(){
13423 return this.length;
13427 * Returns index within the collection of the passed Object.
13428 * @param {Object} o The item to find the index of.
13429 * @return {Number} index of the item.
13431 indexOf : function(o){
13432 if(!this.items.indexOf){
13433 for(var i = 0, len = this.items.length; i < len; i++){
13434 if(this.items[i] == o) {
13440 return this.items.indexOf(o);
13445 * Returns index within the collection of the passed key.
13446 * @param {String} key The key to find the index of.
13447 * @return {Number} index of the key.
13449 indexOfKey : function(key){
13450 if(!this.keys.indexOf){
13451 for(var i = 0, len = this.keys.length; i < len; i++){
13452 if(this.keys[i] == key) {
13458 return this.keys.indexOf(key);
13463 * Returns the item associated with the passed key OR index. Key has priority over index.
13464 * @param {String/Number} key The key or index of the item.
13465 * @return {Object} The item associated with the passed key.
13467 item : function(key){
13468 if (key === 'length') {
13471 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13472 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13476 * Returns the item at the specified index.
13477 * @param {Number} index The index of the item.
13480 itemAt : function(index){
13481 return this.items[index];
13485 * Returns the item associated with the passed key.
13486 * @param {String/Number} key The key of the item.
13487 * @return {Object} The item associated with the passed key.
13489 key : function(key){
13490 return this.map[key];
13494 * Returns true if the collection contains the passed Object as an item.
13495 * @param {Object} o The Object to look for in the collection.
13496 * @return {Boolean} True if the collection contains the Object as an item.
13498 contains : function(o){
13499 return this.indexOf(o) != -1;
13503 * Returns true if the collection contains the passed Object as a key.
13504 * @param {String} key The key to look for in the collection.
13505 * @return {Boolean} True if the collection contains the Object as a key.
13507 containsKey : function(key){
13508 return typeof this.map[key] != "undefined";
13512 * Removes all items from the collection.
13514 clear : function(){
13519 this.fireEvent("clear");
13523 * Returns the first item in the collection.
13524 * @return {Object} the first item in the collection..
13526 first : function(){
13527 return this.items[0];
13531 * Returns the last item in the collection.
13532 * @return {Object} the last item in the collection..
13535 return this.items[this.length-1];
13538 _sort : function(property, dir, fn){
13539 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13540 fn = fn || function(a, b){
13543 var c = [], k = this.keys, items = this.items;
13544 for(var i = 0, len = items.length; i < len; i++){
13545 c[c.length] = {key: k[i], value: items[i], index: i};
13547 c.sort(function(a, b){
13548 var v = fn(a[property], b[property]) * dsc;
13550 v = (a.index < b.index ? -1 : 1);
13554 for(var i = 0, len = c.length; i < len; i++){
13555 items[i] = c[i].value;
13558 this.fireEvent("sort", this);
13562 * Sorts this collection with the passed comparison function
13563 * @param {String} direction (optional) "ASC" or "DESC"
13564 * @param {Function} fn (optional) comparison function
13566 sort : function(dir, fn){
13567 this._sort("value", dir, fn);
13571 * Sorts this collection by keys
13572 * @param {String} direction (optional) "ASC" or "DESC"
13573 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13575 keySort : function(dir, fn){
13576 this._sort("key", dir, fn || function(a, b){
13577 return String(a).toUpperCase()-String(b).toUpperCase();
13582 * Returns a range of items in this collection
13583 * @param {Number} startIndex (optional) defaults to 0
13584 * @param {Number} endIndex (optional) default to the last item
13585 * @return {Array} An array of items
13587 getRange : function(start, end){
13588 var items = this.items;
13589 if(items.length < 1){
13592 start = start || 0;
13593 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13596 for(var i = start; i <= end; i++) {
13597 r[r.length] = items[i];
13600 for(var i = start; i >= end; i--) {
13601 r[r.length] = items[i];
13608 * Filter the <i>objects</i> in this collection by a specific property.
13609 * Returns a new collection that has been filtered.
13610 * @param {String} property A property on your objects
13611 * @param {String/RegExp} value Either string that the property values
13612 * should start with or a RegExp to test against the property
13613 * @return {MixedCollection} The new filtered collection
13615 filter : function(property, value){
13616 if(!value.exec){ // not a regex
13617 value = String(value);
13618 if(value.length == 0){
13619 return this.clone();
13621 value = new RegExp("^" + Roo.escapeRe(value), "i");
13623 return this.filterBy(function(o){
13624 return o && value.test(o[property]);
13629 * Filter by a function. * Returns a new collection that has been filtered.
13630 * The passed function will be called with each
13631 * object in the collection. If the function returns true, the value is included
13632 * otherwise it is filtered.
13633 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13634 * @param {Object} scope (optional) The scope of the function (defaults to this)
13635 * @return {MixedCollection} The new filtered collection
13637 filterBy : function(fn, scope){
13638 var r = new Roo.util.MixedCollection();
13639 r.getKey = this.getKey;
13640 var k = this.keys, it = this.items;
13641 for(var i = 0, len = it.length; i < len; i++){
13642 if(fn.call(scope||this, it[i], k[i])){
13643 r.add(k[i], it[i]);
13650 * Creates a duplicate of this collection
13651 * @return {MixedCollection}
13653 clone : function(){
13654 var r = new Roo.util.MixedCollection();
13655 var k = this.keys, it = this.items;
13656 for(var i = 0, len = it.length; i < len; i++){
13657 r.add(k[i], it[i]);
13659 r.getKey = this.getKey;
13664 * Returns the item associated with the passed key or index.
13666 * @param {String/Number} key The key or index of the item.
13667 * @return {Object} The item associated with the passed key.
13669 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13671 * Ext JS Library 1.1.1
13672 * Copyright(c) 2006-2007, Ext JS, LLC.
13674 * Originally Released Under LGPL - original licence link has changed is not relivant.
13677 * <script type="text/javascript">
13680 * @class Roo.util.JSON
13681 * Modified version of Douglas Crockford"s json.js that doesn"t
13682 * mess with the Object prototype
13683 * http://www.json.org/js.html
13686 Roo.util.JSON = new (function(){
13687 var useHasOwn = {}.hasOwnProperty ? true : false;
13689 // crashes Safari in some instances
13690 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13692 var pad = function(n) {
13693 return n < 10 ? "0" + n : n;
13706 var encodeString = function(s){
13707 if (/["\\\x00-\x1f]/.test(s)) {
13708 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13713 c = b.charCodeAt();
13715 Math.floor(c / 16).toString(16) +
13716 (c % 16).toString(16);
13719 return '"' + s + '"';
13722 var encodeArray = function(o){
13723 var a = ["["], b, i, l = o.length, v;
13724 for (i = 0; i < l; i += 1) {
13726 switch (typeof v) {
13735 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13743 var encodeDate = function(o){
13744 return '"' + o.getFullYear() + "-" +
13745 pad(o.getMonth() + 1) + "-" +
13746 pad(o.getDate()) + "T" +
13747 pad(o.getHours()) + ":" +
13748 pad(o.getMinutes()) + ":" +
13749 pad(o.getSeconds()) + '"';
13753 * Encodes an Object, Array or other value
13754 * @param {Mixed} o The variable to encode
13755 * @return {String} The JSON string
13757 this.encode = function(o)
13759 // should this be extended to fully wrap stringify..
13761 if(typeof o == "undefined" || o === null){
13763 }else if(o instanceof Array){
13764 return encodeArray(o);
13765 }else if(o instanceof Date){
13766 return encodeDate(o);
13767 }else if(typeof o == "string"){
13768 return encodeString(o);
13769 }else if(typeof o == "number"){
13770 return isFinite(o) ? String(o) : "null";
13771 }else if(typeof o == "boolean"){
13774 var a = ["{"], b, i, v;
13776 if(!useHasOwn || o.hasOwnProperty(i)) {
13778 switch (typeof v) {
13787 a.push(this.encode(i), ":",
13788 v === null ? "null" : this.encode(v));
13799 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13800 * @param {String} json The JSON string
13801 * @return {Object} The resulting object
13803 this.decode = function(json){
13805 return /** eval:var:json */ eval("(" + json + ')');
13809 * Shorthand for {@link Roo.util.JSON#encode}
13810 * @member Roo encode
13812 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13814 * Shorthand for {@link Roo.util.JSON#decode}
13815 * @member Roo decode
13817 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13820 * Ext JS Library 1.1.1
13821 * Copyright(c) 2006-2007, Ext JS, LLC.
13823 * Originally Released Under LGPL - original licence link has changed is not relivant.
13826 * <script type="text/javascript">
13830 * @class Roo.util.Format
13831 * Reusable data formatting functions
13834 Roo.util.Format = function(){
13835 var trimRe = /^\s+|\s+$/g;
13838 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13839 * @param {String} value The string to truncate
13840 * @param {Number} length The maximum length to allow before truncating
13841 * @return {String} The converted text
13843 ellipsis : function(value, len){
13844 if(value && value.length > len){
13845 return value.substr(0, len-3)+"...";
13851 * Checks a reference and converts it to empty string if it is undefined
13852 * @param {Mixed} value Reference to check
13853 * @return {Mixed} Empty string if converted, otherwise the original value
13855 undef : function(value){
13856 return typeof value != "undefined" ? value : "";
13860 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13861 * @param {String} value The string to encode
13862 * @return {String} The encoded text
13864 htmlEncode : function(value){
13865 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
13869 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13870 * @param {String} value The string to decode
13871 * @return {String} The decoded text
13873 htmlDecode : function(value){
13874 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
13878 * Trims any whitespace from either side of a string
13879 * @param {String} value The text to trim
13880 * @return {String} The trimmed text
13882 trim : function(value){
13883 return String(value).replace(trimRe, "");
13887 * Returns a substring from within an original string
13888 * @param {String} value The original text
13889 * @param {Number} start The start index of the substring
13890 * @param {Number} length The length of the substring
13891 * @return {String} The substring
13893 substr : function(value, start, length){
13894 return String(value).substr(start, length);
13898 * Converts a string to all lower case letters
13899 * @param {String} value The text to convert
13900 * @return {String} The converted text
13902 lowercase : function(value){
13903 return String(value).toLowerCase();
13907 * Converts a string to all upper case letters
13908 * @param {String} value The text to convert
13909 * @return {String} The converted text
13911 uppercase : function(value){
13912 return String(value).toUpperCase();
13916 * Converts the first character only of a string to upper case
13917 * @param {String} value The text to convert
13918 * @return {String} The converted text
13920 capitalize : function(value){
13921 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13925 call : function(value, fn){
13926 if(arguments.length > 2){
13927 var args = Array.prototype.slice.call(arguments, 2);
13928 args.unshift(value);
13930 return /** eval:var:value */ eval(fn).apply(window, args);
13932 /** eval:var:value */
13933 return /** eval:var:value */ eval(fn).call(window, value);
13939 * safer version of Math.toFixed..??/
13940 * @param {Number/String} value The numeric value to format
13941 * @param {Number/String} value Decimal places
13942 * @return {String} The formatted currency string
13944 toFixed : function(v, n)
13946 // why not use to fixed - precision is buggered???
13948 return Math.round(v-0);
13950 var fact = Math.pow(10,n+1);
13951 v = (Math.round((v-0)*fact))/fact;
13952 var z = (''+fact).substring(2);
13953 if (v == Math.floor(v)) {
13954 return Math.floor(v) + '.' + z;
13957 // now just padd decimals..
13958 var ps = String(v).split('.');
13959 var fd = (ps[1] + z);
13960 var r = fd.substring(0,n);
13961 var rm = fd.substring(n);
13963 return ps[0] + '.' + r;
13965 r*=1; // turn it into a number;
13967 if (String(r).length != n) {
13970 r = String(r).substring(1); // chop the end off.
13973 return ps[0] + '.' + r;
13978 * Format a number as US currency
13979 * @param {Number/String} value The numeric value to format
13980 * @return {String} The formatted currency string
13982 usMoney : function(v){
13983 return '$' + Roo.util.Format.number(v);
13988 * eventually this should probably emulate php's number_format
13989 * @param {Number/String} value The numeric value to format
13990 * @param {Number} decimals number of decimal places
13991 * @param {String} delimiter for thousands (default comma)
13992 * @return {String} The formatted currency string
13994 number : function(v, decimals, thousandsDelimiter)
13996 // multiply and round.
13997 decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13998 thousandsDelimiter = typeof(thousandsDelimiter) == 'undefined' ? ',' : thousandsDelimiter;
14000 var mul = Math.pow(10, decimals);
14001 var zero = String(mul).substring(1);
14002 v = (Math.round((v-0)*mul))/mul;
14004 // if it's '0' number.. then
14006 //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
14008 var ps = v.split('.');
14011 var r = /(\d+)(\d{3})/;
14014 if(thousandsDelimiter.length != 0) {
14015 whole = whole.replace(/\B(?=(\d{3})+(?!\d))/g, thousandsDelimiter );
14020 (decimals ? ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
14021 // does not have decimals
14022 (decimals ? ('.' + zero) : '');
14025 return whole + sub ;
14029 * Parse a value into a formatted date using the specified format pattern.
14030 * @param {Mixed} value The value to format
14031 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
14032 * @return {String} The formatted date string
14034 date : function(v, format){
14038 if(!(v instanceof Date)){
14039 v = new Date(Date.parse(v));
14041 return v.dateFormat(format || Roo.util.Format.defaults.date);
14045 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
14046 * @param {String} format Any valid date format string
14047 * @return {Function} The date formatting function
14049 dateRenderer : function(format){
14050 return function(v){
14051 return Roo.util.Format.date(v, format);
14056 stripTagsRE : /<\/?[^>]+>/gi,
14059 * Strips all HTML tags
14060 * @param {Mixed} value The text from which to strip tags
14061 * @return {String} The stripped text
14063 stripTags : function(v){
14064 return !v ? v : String(v).replace(this.stripTagsRE, "");
14068 * Size in Mb,Gb etc.
14069 * @param {Number} value The number to be formated
14070 * @param {number} decimals how many decimal places
14071 * @return {String} the formated string
14073 size : function(value, decimals)
14075 var sizes = ['b', 'k', 'M', 'G', 'T'];
14079 var i = parseInt(Math.floor(Math.log(value) / Math.log(1024)));
14080 return Roo.util.Format.number(value/ Math.pow(1024, i) ,decimals) + sizes[i];
14087 Roo.util.Format.defaults = {
14091 * Ext JS Library 1.1.1
14092 * Copyright(c) 2006-2007, Ext JS, LLC.
14094 * Originally Released Under LGPL - original licence link has changed is not relivant.
14097 * <script type="text/javascript">
14104 * @class Roo.MasterTemplate
14105 * @extends Roo.Template
14106 * Provides a template that can have child templates. The syntax is:
14108 var t = new Roo.MasterTemplate(
14109 '<select name="{name}">',
14110 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
14113 t.add('options', {value: 'foo', text: 'bar'});
14114 // or you can add multiple child elements in one shot
14115 t.addAll('options', [
14116 {value: 'foo', text: 'bar'},
14117 {value: 'foo2', text: 'bar2'},
14118 {value: 'foo3', text: 'bar3'}
14120 // then append, applying the master template values
14121 t.append('my-form', {name: 'my-select'});
14123 * A name attribute for the child template is not required if you have only one child
14124 * template or you want to refer to them by index.
14126 Roo.MasterTemplate = function(){
14127 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
14128 this.originalHtml = this.html;
14130 var m, re = this.subTemplateRe;
14133 while(m = re.exec(this.html)){
14134 var name = m[1], content = m[2];
14139 tpl : new Roo.Template(content)
14142 st[name] = st[subIndex];
14144 st[subIndex].tpl.compile();
14145 st[subIndex].tpl.call = this.call.createDelegate(this);
14148 this.subCount = subIndex;
14151 Roo.extend(Roo.MasterTemplate, Roo.Template, {
14153 * The regular expression used to match sub templates
14157 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
14160 * Applies the passed values to a child template.
14161 * @param {String/Number} name (optional) The name or index of the child template
14162 * @param {Array/Object} values The values to be applied to the template
14163 * @return {MasterTemplate} this
14165 add : function(name, values){
14166 if(arguments.length == 1){
14167 values = arguments[0];
14170 var s = this.subs[name];
14171 s.buffer[s.buffer.length] = s.tpl.apply(values);
14176 * Applies all the passed values to a child template.
14177 * @param {String/Number} name (optional) The name or index of the child template
14178 * @param {Array} values The values to be applied to the template, this should be an array of objects.
14179 * @param {Boolean} reset (optional) True to reset the template first
14180 * @return {MasterTemplate} this
14182 fill : function(name, values, reset){
14184 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
14192 for(var i = 0, len = values.length; i < len; i++){
14193 this.add(name, values[i]);
14199 * Resets the template for reuse
14200 * @return {MasterTemplate} this
14202 reset : function(){
14204 for(var i = 0; i < this.subCount; i++){
14210 applyTemplate : function(values){
14212 var replaceIndex = -1;
14213 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
14214 return s[++replaceIndex].buffer.join("");
14216 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
14219 apply : function(){
14220 return this.applyTemplate.apply(this, arguments);
14223 compile : function(){return this;}
14227 * Alias for fill().
14230 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
14232 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
14233 * var tpl = Roo.MasterTemplate.from('element-id');
14234 * @param {String/HTMLElement} el
14235 * @param {Object} config
14238 Roo.MasterTemplate.from = function(el, config){
14239 el = Roo.getDom(el);
14240 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
14243 * Ext JS Library 1.1.1
14244 * Copyright(c) 2006-2007, Ext JS, LLC.
14246 * Originally Released Under LGPL - original licence link has changed is not relivant.
14249 * <script type="text/javascript">
14254 * @class Roo.util.CSS
14255 * Utility class for manipulating CSS rules
14258 Roo.util.CSS = function(){
14260 var doc = document;
14262 var camelRe = /(-[a-z])/gi;
14263 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
14267 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
14268 * tag and appended to the HEAD of the document.
14269 * @param {String|Object} cssText The text containing the css rules
14270 * @param {String} id An id to add to the stylesheet for later removal
14271 * @return {StyleSheet}
14273 createStyleSheet : function(cssText, id){
14275 var head = doc.getElementsByTagName("head")[0];
14276 var nrules = doc.createElement("style");
14277 nrules.setAttribute("type", "text/css");
14279 nrules.setAttribute("id", id);
14281 if (typeof(cssText) != 'string') {
14282 // support object maps..
14283 // not sure if this a good idea..
14284 // perhaps it should be merged with the general css handling
14285 // and handle js style props.
14286 var cssTextNew = [];
14287 for(var n in cssText) {
14289 for(var k in cssText[n]) {
14290 citems.push( k + ' : ' +cssText[n][k] + ';' );
14292 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
14295 cssText = cssTextNew.join("\n");
14301 head.appendChild(nrules);
14302 ss = nrules.styleSheet;
14303 ss.cssText = cssText;
14306 nrules.appendChild(doc.createTextNode(cssText));
14308 nrules.cssText = cssText;
14310 head.appendChild(nrules);
14311 ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
14313 this.cacheStyleSheet(ss);
14318 * Removes a style or link tag by id
14319 * @param {String} id The id of the tag
14321 removeStyleSheet : function(id){
14322 var existing = doc.getElementById(id);
14324 existing.parentNode.removeChild(existing);
14329 * Dynamically swaps an existing stylesheet reference for a new one
14330 * @param {String} id The id of an existing link tag to remove
14331 * @param {String} url The href of the new stylesheet to include
14333 swapStyleSheet : function(id, url){
14334 this.removeStyleSheet(id);
14335 var ss = doc.createElement("link");
14336 ss.setAttribute("rel", "stylesheet");
14337 ss.setAttribute("type", "text/css");
14338 ss.setAttribute("id", id);
14339 ss.setAttribute("href", url);
14340 doc.getElementsByTagName("head")[0].appendChild(ss);
14344 * Refresh the rule cache if you have dynamically added stylesheets
14345 * @return {Object} An object (hash) of rules indexed by selector
14347 refreshCache : function(){
14348 return this.getRules(true);
14352 cacheStyleSheet : function(stylesheet){
14356 try{// try catch for cross domain access issue
14357 var ssRules = stylesheet.cssRules || stylesheet.rules;
14358 for(var j = ssRules.length-1; j >= 0; --j){
14359 rules[ssRules[j].selectorText] = ssRules[j];
14365 * Gets all css rules for the document
14366 * @param {Boolean} refreshCache true to refresh the internal cache
14367 * @return {Object} An object (hash) of rules indexed by selector
14369 getRules : function(refreshCache){
14370 if(rules == null || refreshCache){
14372 var ds = doc.styleSheets;
14373 for(var i =0, len = ds.length; i < len; i++){
14375 this.cacheStyleSheet(ds[i]);
14383 * Gets an an individual CSS rule by selector(s)
14384 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
14385 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
14386 * @return {CSSRule} The CSS rule or null if one is not found
14388 getRule : function(selector, refreshCache){
14389 var rs = this.getRules(refreshCache);
14390 if(!(selector instanceof Array)){
14391 return rs[selector];
14393 for(var i = 0; i < selector.length; i++){
14394 if(rs[selector[i]]){
14395 return rs[selector[i]];
14403 * Updates a rule property
14404 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
14405 * @param {String} property The css property
14406 * @param {String} value The new value for the property
14407 * @return {Boolean} true If a rule was found and updated
14409 updateRule : function(selector, property, value){
14410 if(!(selector instanceof Array)){
14411 var rule = this.getRule(selector);
14413 rule.style[property.replace(camelRe, camelFn)] = value;
14417 for(var i = 0; i < selector.length; i++){
14418 if(this.updateRule(selector[i], property, value)){
14428 * Ext JS Library 1.1.1
14429 * Copyright(c) 2006-2007, Ext JS, LLC.
14431 * Originally Released Under LGPL - original licence link has changed is not relivant.
14434 * <script type="text/javascript">
14440 * @class Roo.util.ClickRepeater
14441 * @extends Roo.util.Observable
14443 * A wrapper class which can be applied to any element. Fires a "click" event while the
14444 * mouse is pressed. The interval between firings may be specified in the config but
14445 * defaults to 10 milliseconds.
14447 * Optionally, a CSS class may be applied to the element during the time it is pressed.
14449 * @cfg {String/HTMLElement/Element} el The element to act as a button.
14450 * @cfg {Number} delay The initial delay before the repeating event begins firing.
14451 * Similar to an autorepeat key delay.
14452 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14453 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14454 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14455 * "interval" and "delay" are ignored. "immediate" is honored.
14456 * @cfg {Boolean} preventDefault True to prevent the default click event
14457 * @cfg {Boolean} stopDefault True to stop the default click event
14460 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
14461 * 2007-02-02 jvs Renamed to ClickRepeater
14462 * 2007-02-03 jvs Modifications for FF Mac and Safari
14465 * @param {String/HTMLElement/Element} el The element to listen on
14466 * @param {Object} config
14468 Roo.util.ClickRepeater = function(el, config)
14470 this.el = Roo.get(el);
14471 this.el.unselectable();
14473 Roo.apply(this, config);
14478 * Fires when the mouse button is depressed.
14479 * @param {Roo.util.ClickRepeater} this
14481 "mousedown" : true,
14484 * Fires on a specified interval during the time the element is pressed.
14485 * @param {Roo.util.ClickRepeater} this
14490 * Fires when the mouse key is released.
14491 * @param {Roo.util.ClickRepeater} this
14496 this.el.on("mousedown", this.handleMouseDown, this);
14497 if(this.preventDefault || this.stopDefault){
14498 this.el.on("click", function(e){
14499 if(this.preventDefault){
14500 e.preventDefault();
14502 if(this.stopDefault){
14508 // allow inline handler
14510 this.on("click", this.handler, this.scope || this);
14513 Roo.util.ClickRepeater.superclass.constructor.call(this);
14516 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14519 preventDefault : true,
14520 stopDefault : false,
14524 handleMouseDown : function(){
14525 clearTimeout(this.timer);
14527 if(this.pressClass){
14528 this.el.addClass(this.pressClass);
14530 this.mousedownTime = new Date();
14532 Roo.get(document).on("mouseup", this.handleMouseUp, this);
14533 this.el.on("mouseout", this.handleMouseOut, this);
14535 this.fireEvent("mousedown", this);
14536 this.fireEvent("click", this);
14538 this.timer = this.click.defer(this.delay || this.interval, this);
14542 click : function(){
14543 this.fireEvent("click", this);
14544 this.timer = this.click.defer(this.getInterval(), this);
14548 getInterval: function(){
14549 if(!this.accelerate){
14550 return this.interval;
14552 var pressTime = this.mousedownTime.getElapsed();
14553 if(pressTime < 500){
14555 }else if(pressTime < 1700){
14557 }else if(pressTime < 2600){
14559 }else if(pressTime < 3500){
14561 }else if(pressTime < 4400){
14563 }else if(pressTime < 5300){
14565 }else if(pressTime < 6200){
14573 handleMouseOut : function(){
14574 clearTimeout(this.timer);
14575 if(this.pressClass){
14576 this.el.removeClass(this.pressClass);
14578 this.el.on("mouseover", this.handleMouseReturn, this);
14582 handleMouseReturn : function(){
14583 this.el.un("mouseover", this.handleMouseReturn);
14584 if(this.pressClass){
14585 this.el.addClass(this.pressClass);
14591 handleMouseUp : function(){
14592 clearTimeout(this.timer);
14593 this.el.un("mouseover", this.handleMouseReturn);
14594 this.el.un("mouseout", this.handleMouseOut);
14595 Roo.get(document).un("mouseup", this.handleMouseUp);
14596 this.el.removeClass(this.pressClass);
14597 this.fireEvent("mouseup", this);
14600 * @class Roo.util.Clipboard
14606 Roo.util.Clipboard = {
14608 * Writes a string to the clipboard - using the Clipboard API if https, otherwise using text area.
14609 * @param {String} text to copy to clipboard
14611 write : function(text) {
14612 // navigator clipboard api needs a secure context (https)
14613 if (navigator.clipboard && window.isSecureContext) {
14614 // navigator clipboard api method'
14615 navigator.clipboard.writeText(text);
14618 // text area method
14619 var ta = document.createElement("textarea");
14621 // make the textarea out of viewport
14622 ta.style.position = "fixed";
14623 ta.style.left = "-999999px";
14624 ta.style.top = "-999999px";
14625 document.body.appendChild(ta);
14628 document.execCommand('copy');
14638 * Ext JS Library 1.1.1
14639 * Copyright(c) 2006-2007, Ext JS, LLC.
14641 * Originally Released Under LGPL - original licence link has changed is not relivant.
14644 * <script type="text/javascript">
14649 * @class Roo.KeyNav
14650 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
14651 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14652 * way to implement custom navigation schemes for any UI component.</p>
14653 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14654 * pageUp, pageDown, del, home, end. Usage:</p>
14656 var nav = new Roo.KeyNav("my-element", {
14657 "left" : function(e){
14658 this.moveLeft(e.ctrlKey);
14660 "right" : function(e){
14661 this.moveRight(e.ctrlKey);
14663 "enter" : function(e){
14670 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14671 * @param {Object} config The config
14673 Roo.KeyNav = function(el, config){
14674 this.el = Roo.get(el);
14675 Roo.apply(this, config);
14676 if(!this.disabled){
14677 this.disabled = true;
14682 Roo.KeyNav.prototype = {
14684 * @cfg {Boolean} disabled
14685 * True to disable this KeyNav instance (defaults to false)
14689 * @cfg {String} defaultEventAction
14690 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
14691 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14692 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14694 defaultEventAction: "stopEvent",
14696 * @cfg {Boolean} forceKeyDown
14697 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
14698 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14699 * handle keydown instead of keypress.
14701 forceKeyDown : false,
14704 prepareEvent : function(e){
14705 var k = e.getKey();
14706 var h = this.keyToHandler[k];
14707 //if(h && this[h]){
14708 // e.stopPropagation();
14710 if(Roo.isSafari && h && k >= 37 && k <= 40){
14716 relay : function(e){
14717 var k = e.getKey();
14718 var h = this.keyToHandler[k];
14720 if(this.doRelay(e, this[h], h) !== true){
14721 e[this.defaultEventAction]();
14727 doRelay : function(e, h, hname){
14728 return h.call(this.scope || this, e);
14731 // possible handlers
14745 // quick lookup hash
14762 * Enable this KeyNav
14764 enable: function(){
14766 // ie won't do special keys on keypress, no one else will repeat keys with keydown
14767 // the EventObject will normalize Safari automatically
14768 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14769 this.el.on("keydown", this.relay, this);
14771 this.el.on("keydown", this.prepareEvent, this);
14772 this.el.on("keypress", this.relay, this);
14774 this.disabled = false;
14779 * Disable this KeyNav
14781 disable: function(){
14782 if(!this.disabled){
14783 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14784 this.el.un("keydown", this.relay);
14786 this.el.un("keydown", this.prepareEvent);
14787 this.el.un("keypress", this.relay);
14789 this.disabled = true;
14794 * Ext JS Library 1.1.1
14795 * Copyright(c) 2006-2007, Ext JS, LLC.
14797 * Originally Released Under LGPL - original licence link has changed is not relivant.
14800 * <script type="text/javascript">
14805 * @class Roo.KeyMap
14806 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14807 * The constructor accepts the same config object as defined by {@link #addBinding}.
14808 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14809 * combination it will call the function with this signature (if the match is a multi-key
14810 * combination the callback will still be called only once): (String key, Roo.EventObject e)
14811 * A KeyMap can also handle a string representation of keys.<br />
14814 // map one key by key code
14815 var map = new Roo.KeyMap("my-element", {
14816 key: 13, // or Roo.EventObject.ENTER
14821 // map multiple keys to one action by string
14822 var map = new Roo.KeyMap("my-element", {
14828 // map multiple keys to multiple actions by strings and array of codes
14829 var map = new Roo.KeyMap("my-element", [
14832 fn: function(){ alert("Return was pressed"); }
14835 fn: function(){ alert('a, b or c was pressed'); }
14840 fn: function(){ alert('Control + shift + tab was pressed.'); }
14844 * <b>Note: A KeyMap starts enabled</b>
14846 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14847 * @param {Object} config The config (see {@link #addBinding})
14848 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14850 Roo.KeyMap = function(el, config, eventName){
14851 this.el = Roo.get(el);
14852 this.eventName = eventName || "keydown";
14853 this.bindings = [];
14855 this.addBinding(config);
14860 Roo.KeyMap.prototype = {
14862 * True to stop the event from bubbling and prevent the default browser action if the
14863 * key was handled by the KeyMap (defaults to false)
14869 * Add a new binding to this KeyMap. The following config object properties are supported:
14871 Property Type Description
14872 ---------- --------------- ----------------------------------------------------------------------
14873 key String/Array A single keycode or an array of keycodes to handle
14874 shift Boolean True to handle key only when shift is pressed (defaults to false)
14875 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
14876 alt Boolean True to handle key only when alt is pressed (defaults to false)
14877 fn Function The function to call when KeyMap finds the expected key combination
14878 scope Object The scope of the callback function
14884 var map = new Roo.KeyMap(document, {
14885 key: Roo.EventObject.ENTER,
14890 //Add a new binding to the existing KeyMap later
14898 * @param {Object/Array} config A single KeyMap config or an array of configs
14900 addBinding : function(config){
14901 if(config instanceof Array){
14902 for(var i = 0, len = config.length; i < len; i++){
14903 this.addBinding(config[i]);
14907 var keyCode = config.key,
14908 shift = config.shift,
14909 ctrl = config.ctrl,
14912 scope = config.scope;
14913 if(typeof keyCode == "string"){
14915 var keyString = keyCode.toUpperCase();
14916 for(var j = 0, len = keyString.length; j < len; j++){
14917 ks.push(keyString.charCodeAt(j));
14921 var keyArray = keyCode instanceof Array;
14922 var handler = function(e){
14923 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
14924 var k = e.getKey();
14926 for(var i = 0, len = keyCode.length; i < len; i++){
14927 if(keyCode[i] == k){
14928 if(this.stopEvent){
14931 fn.call(scope || window, k, e);
14937 if(this.stopEvent){
14940 fn.call(scope || window, k, e);
14945 this.bindings.push(handler);
14949 * Shorthand for adding a single key listener
14950 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14951 * following options:
14952 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14953 * @param {Function} fn The function to call
14954 * @param {Object} scope (optional) The scope of the function
14956 on : function(key, fn, scope){
14957 var keyCode, shift, ctrl, alt;
14958 if(typeof key == "object" && !(key instanceof Array)){
14977 handleKeyDown : function(e){
14978 if(this.enabled){ //just in case
14979 var b = this.bindings;
14980 for(var i = 0, len = b.length; i < len; i++){
14981 b[i].call(this, e);
14987 * Returns true if this KeyMap is enabled
14988 * @return {Boolean}
14990 isEnabled : function(){
14991 return this.enabled;
14995 * Enables this KeyMap
14997 enable: function(){
14999 this.el.on(this.eventName, this.handleKeyDown, this);
15000 this.enabled = true;
15005 * Disable this KeyMap
15007 disable: function(){
15009 this.el.removeListener(this.eventName, this.handleKeyDown, this);
15010 this.enabled = false;
15015 * Ext JS Library 1.1.1
15016 * Copyright(c) 2006-2007, Ext JS, LLC.
15018 * Originally Released Under LGPL - original licence link has changed is not relivant.
15021 * <script type="text/javascript">
15026 * @class Roo.util.TextMetrics
15027 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
15028 * wide, in pixels, a given block of text will be.
15031 Roo.util.TextMetrics = function(){
15035 * Measures the size of the specified text
15036 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
15037 * that can affect the size of the rendered text
15038 * @param {String} text The text to measure
15039 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
15040 * in order to accurately measure the text height
15041 * @return {Object} An object containing the text's size {width: (width), height: (height)}
15043 measure : function(el, text, fixedWidth){
15045 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
15048 shared.setFixedWidth(fixedWidth || 'auto');
15049 return shared.getSize(text);
15053 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
15054 * the overhead of multiple calls to initialize the style properties on each measurement.
15055 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
15056 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
15057 * in order to accurately measure the text height
15058 * @return {Roo.util.TextMetrics.Instance} instance The new instance
15060 createInstance : function(el, fixedWidth){
15061 return Roo.util.TextMetrics.Instance(el, fixedWidth);
15068 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
15069 var ml = new Roo.Element(document.createElement('div'));
15070 document.body.appendChild(ml.dom);
15071 ml.position('absolute');
15072 ml.setLeftTop(-1000, -1000);
15076 ml.setWidth(fixedWidth);
15081 * Returns the size of the specified text based on the internal element's style and width properties
15082 * @memberOf Roo.util.TextMetrics.Instance#
15083 * @param {String} text The text to measure
15084 * @return {Object} An object containing the text's size {width: (width), height: (height)}
15086 getSize : function(text){
15088 var s = ml.getSize();
15094 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
15095 * that can affect the size of the rendered text
15096 * @memberOf Roo.util.TextMetrics.Instance#
15097 * @param {String/HTMLElement} el The element, dom node or id
15099 bind : function(el){
15101 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
15106 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
15107 * to set a fixed width in order to accurately measure the text height.
15108 * @memberOf Roo.util.TextMetrics.Instance#
15109 * @param {Number} width The width to set on the element
15111 setFixedWidth : function(width){
15112 ml.setWidth(width);
15116 * Returns the measured width of the specified text
15117 * @memberOf Roo.util.TextMetrics.Instance#
15118 * @param {String} text The text to measure
15119 * @return {Number} width The width in pixels
15121 getWidth : function(text){
15122 ml.dom.style.width = 'auto';
15123 return this.getSize(text).width;
15127 * Returns the measured height of the specified text. For multiline text, be sure to call
15128 * {@link #setFixedWidth} if necessary.
15129 * @memberOf Roo.util.TextMetrics.Instance#
15130 * @param {String} text The text to measure
15131 * @return {Number} height The height in pixels
15133 getHeight : function(text){
15134 return this.getSize(text).height;
15138 instance.bind(bindTo);
15143 // backwards compat
15144 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
15146 * Ext JS Library 1.1.1
15147 * Copyright(c) 2006-2007, Ext JS, LLC.
15149 * Originally Released Under LGPL - original licence link has changed is not relivant.
15152 * <script type="text/javascript">
15156 * @class Roo.state.Provider
15157 * Abstract base class for state provider implementations. This class provides methods
15158 * for encoding and decoding <b>typed</b> variables including dates and defines the
15159 * Provider interface.
15161 Roo.state.Provider = function(){
15163 * @event statechange
15164 * Fires when a state change occurs.
15165 * @param {Provider} this This state provider
15166 * @param {String} key The state key which was changed
15167 * @param {String} value The encoded value for the state
15170 "statechange": true
15173 Roo.state.Provider.superclass.constructor.call(this);
15175 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
15177 * Returns the current value for a key
15178 * @param {String} name The key name
15179 * @param {Mixed} defaultValue A default value to return if the key's value is not found
15180 * @return {Mixed} The state data
15182 get : function(name, defaultValue){
15183 return typeof this.state[name] == "undefined" ?
15184 defaultValue : this.state[name];
15188 * Clears a value from the state
15189 * @param {String} name The key name
15191 clear : function(name){
15192 delete this.state[name];
15193 this.fireEvent("statechange", this, name, null);
15197 * Sets the value for a key
15198 * @param {String} name The key name
15199 * @param {Mixed} value The value to set
15201 set : function(name, value){
15202 this.state[name] = value;
15203 this.fireEvent("statechange", this, name, value);
15207 * Decodes a string previously encoded with {@link #encodeValue}.
15208 * @param {String} value The value to decode
15209 * @return {Mixed} The decoded value
15211 decodeValue : function(cookie){
15212 var re = /^(a|n|d|b|s|o)\:(.*)$/;
15213 var matches = re.exec(unescape(cookie));
15214 if(!matches || !matches[1]) {
15215 return; // non state cookie
15217 var type = matches[1];
15218 var v = matches[2];
15221 return parseFloat(v);
15223 return new Date(Date.parse(v));
15228 var values = v.split("^");
15229 for(var i = 0, len = values.length; i < len; i++){
15230 all.push(this.decodeValue(values[i]));
15235 var values = v.split("^");
15236 for(var i = 0, len = values.length; i < len; i++){
15237 var kv = values[i].split("=");
15238 all[kv[0]] = this.decodeValue(kv[1]);
15247 * Encodes a value including type information. Decode with {@link #decodeValue}.
15248 * @param {Mixed} value The value to encode
15249 * @return {String} The encoded value
15251 encodeValue : function(v){
15253 if(typeof v == "number"){
15255 }else if(typeof v == "boolean"){
15256 enc = "b:" + (v ? "1" : "0");
15257 }else if(v instanceof Date){
15258 enc = "d:" + v.toGMTString();
15259 }else if(v instanceof Array){
15261 for(var i = 0, len = v.length; i < len; i++){
15262 flat += this.encodeValue(v[i]);
15268 }else if(typeof v == "object"){
15271 if(typeof v[key] != "function"){
15272 flat += key + "=" + this.encodeValue(v[key]) + "^";
15275 enc = "o:" + flat.substring(0, flat.length-1);
15279 return escape(enc);
15285 * Ext JS Library 1.1.1
15286 * Copyright(c) 2006-2007, Ext JS, LLC.
15288 * Originally Released Under LGPL - original licence link has changed is not relivant.
15291 * <script type="text/javascript">
15294 * @class Roo.state.Manager
15295 * This is the global state manager. By default all components that are "state aware" check this class
15296 * for state information if you don't pass them a custom state provider. In order for this class
15297 * to be useful, it must be initialized with a provider when your application initializes.
15299 // in your initialization function
15301 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
15303 // supposed you have a {@link Roo.BorderLayout}
15304 var layout = new Roo.BorderLayout(...);
15305 layout.restoreState();
15306 // or a {Roo.BasicDialog}
15307 var dialog = new Roo.BasicDialog(...);
15308 dialog.restoreState();
15312 Roo.state.Manager = function(){
15313 var provider = new Roo.state.Provider();
15317 * Configures the default state provider for your application
15318 * @param {Provider} stateProvider The state provider to set
15320 setProvider : function(stateProvider){
15321 provider = stateProvider;
15325 * Returns the current value for a key
15326 * @param {String} name The key name
15327 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
15328 * @return {Mixed} The state data
15330 get : function(key, defaultValue){
15331 return provider.get(key, defaultValue);
15335 * Sets the value for a key
15336 * @param {String} name The key name
15337 * @param {Mixed} value The state data
15339 set : function(key, value){
15340 provider.set(key, value);
15344 * Clears a value from the state
15345 * @param {String} name The key name
15347 clear : function(key){
15348 provider.clear(key);
15352 * Gets the currently configured state provider
15353 * @return {Provider} The state provider
15355 getProvider : function(){
15362 * Ext JS Library 1.1.1
15363 * Copyright(c) 2006-2007, Ext JS, LLC.
15365 * Originally Released Under LGPL - original licence link has changed is not relivant.
15368 * <script type="text/javascript">
15371 * @class Roo.state.CookieProvider
15372 * @extends Roo.state.Provider
15373 * The default Provider implementation which saves state via cookies.
15376 var cp = new Roo.state.CookieProvider({
15378 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
15379 domain: "roojs.com"
15381 Roo.state.Manager.setProvider(cp);
15383 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
15384 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
15385 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
15386 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
15387 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
15388 * domain the page is running on including the 'www' like 'www.roojs.com')
15389 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
15391 * Create a new CookieProvider
15392 * @param {Object} config The configuration object
15394 Roo.state.CookieProvider = function(config){
15395 Roo.state.CookieProvider.superclass.constructor.call(this);
15397 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
15398 this.domain = null;
15399 this.secure = false;
15400 Roo.apply(this, config);
15401 this.state = this.readCookies();
15404 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
15406 set : function(name, value){
15407 if(typeof value == "undefined" || value === null){
15411 this.setCookie(name, value);
15412 Roo.state.CookieProvider.superclass.set.call(this, name, value);
15416 clear : function(name){
15417 this.clearCookie(name);
15418 Roo.state.CookieProvider.superclass.clear.call(this, name);
15422 readCookies : function(){
15424 var c = document.cookie + ";";
15425 var re = /\s?(.*?)=(.*?);/g;
15427 while((matches = re.exec(c)) != null){
15428 var name = matches[1];
15429 var value = matches[2];
15430 if(name && name.substring(0,3) == "ys-"){
15431 cookies[name.substr(3)] = this.decodeValue(value);
15438 setCookie : function(name, value){
15439 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
15440 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
15441 ((this.path == null) ? "" : ("; path=" + this.path)) +
15442 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15443 ((this.secure == true) ? "; secure" : "");
15447 clearCookie : function(name){
15448 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
15449 ((this.path == null) ? "" : ("; path=" + this.path)) +
15450 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15451 ((this.secure == true) ? "; secure" : "");
15455 * Ext JS Library 1.1.1
15456 * Copyright(c) 2006-2007, Ext JS, LLC.
15458 * Originally Released Under LGPL - original licence link has changed is not relivant.
15461 * <script type="text/javascript">
15466 * @class Roo.ComponentMgr
15467 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
15470 Roo.ComponentMgr = function(){
15471 var all = new Roo.util.MixedCollection();
15475 * Registers a component.
15476 * @param {Roo.Component} c The component
15478 register : function(c){
15483 * Unregisters a component.
15484 * @param {Roo.Component} c The component
15486 unregister : function(c){
15491 * Returns a component by id
15492 * @param {String} id The component id
15494 get : function(id){
15495 return all.get(id);
15499 * Registers a function that will be called when a specified component is added to ComponentMgr
15500 * @param {String} id The component id
15501 * @param {Funtction} fn The callback function
15502 * @param {Object} scope The scope of the callback
15504 onAvailable : function(id, fn, scope){
15505 all.on("add", function(index, o){
15507 fn.call(scope || o, o);
15508 all.un("add", fn, scope);
15515 * Ext JS Library 1.1.1
15516 * Copyright(c) 2006-2007, Ext JS, LLC.
15518 * Originally Released Under LGPL - original licence link has changed is not relivant.
15521 * <script type="text/javascript">
15525 * @class Roo.Component
15526 * @extends Roo.util.Observable
15527 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
15528 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
15529 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15530 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15531 * All visual components (widgets) that require rendering into a layout should subclass Component.
15533 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
15534 * 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
15535 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
15537 Roo.Component = function(config){
15538 config = config || {};
15539 if(config.tagName || config.dom || typeof config == "string"){ // element object
15540 config = {el: config, id: config.id || config};
15542 this.initialConfig = config;
15544 Roo.apply(this, config);
15548 * Fires after the component is disabled.
15549 * @param {Roo.Component} this
15554 * Fires after the component is enabled.
15555 * @param {Roo.Component} this
15559 * @event beforeshow
15560 * Fires before the component is shown. Return false to stop the show.
15561 * @param {Roo.Component} this
15566 * Fires after the component is shown.
15567 * @param {Roo.Component} this
15571 * @event beforehide
15572 * Fires before the component is hidden. Return false to stop the hide.
15573 * @param {Roo.Component} this
15578 * Fires after the component is hidden.
15579 * @param {Roo.Component} this
15583 * @event beforerender
15584 * Fires before the component is rendered. Return false to stop the render.
15585 * @param {Roo.Component} this
15587 beforerender : true,
15590 * Fires after the component is rendered.
15591 * @param {Roo.Component} this
15595 * @event beforedestroy
15596 * Fires before the component is destroyed. Return false to stop the destroy.
15597 * @param {Roo.Component} this
15599 beforedestroy : true,
15602 * Fires after the component is destroyed.
15603 * @param {Roo.Component} this
15608 this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
15610 Roo.ComponentMgr.register(this);
15611 Roo.Component.superclass.constructor.call(this);
15612 this.initComponent();
15613 if(this.renderTo){ // not supported by all components yet. use at your own risk!
15614 this.render(this.renderTo);
15615 delete this.renderTo;
15620 Roo.Component.AUTO_ID = 1000;
15622 Roo.extend(Roo.Component, Roo.util.Observable, {
15624 * @scope Roo.Component.prototype
15626 * true if this component is hidden. Read-only.
15631 * true if this component is disabled. Read-only.
15636 * true if this component has been rendered. Read-only.
15640 /** @cfg {String} disableClass
15641 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15643 disabledClass : "x-item-disabled",
15644 /** @cfg {Boolean} allowDomMove
15645 * Whether the component can move the Dom node when rendering (defaults to true).
15647 allowDomMove : true,
15648 /** @cfg {String} hideMode (display|visibility)
15649 * How this component should hidden. Supported values are
15650 * "visibility" (css visibility), "offsets" (negative offset position) and
15651 * "display" (css display) - defaults to "display".
15653 hideMode: 'display',
15656 ctype : "Roo.Component",
15659 * @cfg {String} actionMode
15660 * which property holds the element that used for hide() / show() / disable() / enable()
15661 * default is 'el' for forms you probably want to set this to fieldEl
15666 getActionEl : function(){
15667 return this[this.actionMode];
15670 initComponent : Roo.emptyFn,
15672 * If this is a lazy rendering component, render it to its container element.
15673 * @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.
15675 render : function(container, position){
15681 if(this.fireEvent("beforerender", this) === false){
15685 if(!container && this.el){
15686 this.el = Roo.get(this.el);
15687 container = this.el.dom.parentNode;
15688 this.allowDomMove = false;
15690 this.container = Roo.get(container);
15691 this.rendered = true;
15692 if(position !== undefined){
15693 if(typeof position == 'number'){
15694 position = this.container.dom.childNodes[position];
15696 position = Roo.getDom(position);
15699 this.onRender(this.container, position || null);
15701 this.el.addClass(this.cls);
15705 this.el.applyStyles(this.style);
15708 this.fireEvent("render", this);
15709 this.afterRender(this.container);
15722 // default function is not really useful
15723 onRender : function(ct, position){
15725 this.el = Roo.get(this.el);
15726 if(this.allowDomMove !== false){
15727 ct.dom.insertBefore(this.el.dom, position);
15733 getAutoCreate : function(){
15734 var cfg = typeof this.autoCreate == "object" ?
15735 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15736 if(this.id && !cfg.id){
15743 afterRender : Roo.emptyFn,
15746 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15747 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15749 destroy : function(){
15750 if(this.fireEvent("beforedestroy", this) !== false){
15751 this.purgeListeners();
15752 this.beforeDestroy();
15754 this.el.removeAllListeners();
15756 if(this.actionMode == "container"){
15757 this.container.remove();
15761 Roo.ComponentMgr.unregister(this);
15762 this.fireEvent("destroy", this);
15767 beforeDestroy : function(){
15772 onDestroy : function(){
15777 * Returns the underlying {@link Roo.Element}.
15778 * @return {Roo.Element} The element
15780 getEl : function(){
15785 * Returns the id of this component.
15788 getId : function(){
15793 * Try to focus this component.
15794 * @param {Boolean} selectText True to also select the text in this component (if applicable)
15795 * @return {Roo.Component} this
15797 focus : function(selectText){
15800 if(selectText === true){
15801 this.el.dom.select();
15816 * Disable this component.
15817 * @return {Roo.Component} this
15819 disable : function(){
15823 this.disabled = true;
15824 this.fireEvent("disable", this);
15829 onDisable : function(){
15830 this.getActionEl().addClass(this.disabledClass);
15831 this.el.dom.disabled = true;
15835 * Enable this component.
15836 * @return {Roo.Component} this
15838 enable : function(){
15842 this.disabled = false;
15843 this.fireEvent("enable", this);
15848 onEnable : function(){
15849 this.getActionEl().removeClass(this.disabledClass);
15850 this.el.dom.disabled = false;
15854 * Convenience function for setting disabled/enabled by boolean.
15855 * @param {Boolean} disabled
15857 setDisabled : function(disabled){
15858 this[disabled ? "disable" : "enable"]();
15862 * Show this component.
15863 * @return {Roo.Component} this
15866 if(this.fireEvent("beforeshow", this) !== false){
15867 this.hidden = false;
15871 this.fireEvent("show", this);
15877 onShow : function(){
15878 var ae = this.getActionEl();
15879 if(this.hideMode == 'visibility'){
15880 ae.dom.style.visibility = "visible";
15881 }else if(this.hideMode == 'offsets'){
15882 ae.removeClass('x-hidden');
15884 ae.dom.style.display = "";
15889 * Hide this component.
15890 * @return {Roo.Component} this
15893 if(this.fireEvent("beforehide", this) !== false){
15894 this.hidden = true;
15898 this.fireEvent("hide", this);
15904 onHide : function(){
15905 var ae = this.getActionEl();
15906 if(this.hideMode == 'visibility'){
15907 ae.dom.style.visibility = "hidden";
15908 }else if(this.hideMode == 'offsets'){
15909 ae.addClass('x-hidden');
15911 ae.dom.style.display = "none";
15916 * Convenience function to hide or show this component by boolean.
15917 * @param {Boolean} visible True to show, false to hide
15918 * @return {Roo.Component} this
15920 setVisible: function(visible){
15930 * Returns true if this component is visible.
15932 isVisible : function(){
15933 return this.getActionEl().isVisible();
15936 cloneConfig : function(overrides){
15937 overrides = overrides || {};
15938 var id = overrides.id || Roo.id();
15939 var cfg = Roo.applyIf(overrides, this.initialConfig);
15940 cfg.id = id; // prevent dup id
15941 return new this.constructor(cfg);
15945 * Ext JS Library 1.1.1
15946 * Copyright(c) 2006-2007, Ext JS, LLC.
15948 * Originally Released Under LGPL - original licence link has changed is not relivant.
15951 * <script type="text/javascript">
15955 * @class Roo.BoxComponent
15956 * @extends Roo.Component
15957 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
15958 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
15959 * container classes should subclass BoxComponent so that they will work consistently when nested within other Roo
15960 * layout containers.
15962 * @param {Roo.Element/String/Object} config The configuration options.
15964 Roo.BoxComponent = function(config){
15965 Roo.Component.call(this, config);
15969 * Fires after the component is resized.
15970 * @param {Roo.Component} this
15971 * @param {Number} adjWidth The box-adjusted width that was set
15972 * @param {Number} adjHeight The box-adjusted height that was set
15973 * @param {Number} rawWidth The width that was originally specified
15974 * @param {Number} rawHeight The height that was originally specified
15979 * Fires after the component is moved.
15980 * @param {Roo.Component} this
15981 * @param {Number} x The new x position
15982 * @param {Number} y The new y position
15988 Roo.extend(Roo.BoxComponent, Roo.Component, {
15989 // private, set in afterRender to signify that the component has been rendered
15991 // private, used to defer height settings to subclasses
15992 deferHeight: false,
15993 /** @cfg {Number} width
15994 * width (optional) size of component
15996 /** @cfg {Number} height
15997 * height (optional) size of component
16001 * Sets the width and height of the component. This method fires the resize event. This method can accept
16002 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
16003 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
16004 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
16005 * @return {Roo.BoxComponent} this
16007 setSize : function(w, h){
16008 // support for standard size objects
16009 if(typeof w == 'object'){
16014 if(!this.boxReady){
16020 // prevent recalcs when not needed
16021 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
16024 this.lastSize = {width: w, height: h};
16026 var adj = this.adjustSize(w, h);
16027 var aw = adj.width, ah = adj.height;
16028 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
16029 var rz = this.getResizeEl();
16030 if(!this.deferHeight && aw !== undefined && ah !== undefined){
16031 rz.setSize(aw, ah);
16032 }else if(!this.deferHeight && ah !== undefined){
16034 }else if(aw !== undefined){
16037 this.onResize(aw, ah, w, h);
16038 this.fireEvent('resize', this, aw, ah, w, h);
16044 * Gets the current size of the component's underlying element.
16045 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
16047 getSize : function(){
16048 return this.el.getSize();
16052 * Gets the current XY position of the component's underlying element.
16053 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
16054 * @return {Array} The XY position of the element (e.g., [100, 200])
16056 getPosition : function(local){
16057 if(local === true){
16058 return [this.el.getLeft(true), this.el.getTop(true)];
16060 return this.xy || this.el.getXY();
16064 * Gets the current box measurements of the component's underlying element.
16065 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
16066 * @returns {Object} box An object in the format {x, y, width, height}
16068 getBox : function(local){
16069 var s = this.el.getSize();
16071 s.x = this.el.getLeft(true);
16072 s.y = this.el.getTop(true);
16074 var xy = this.xy || this.el.getXY();
16082 * Sets the current box measurements of the component's underlying element.
16083 * @param {Object} box An object in the format {x, y, width, height}
16084 * @returns {Roo.BoxComponent} this
16086 updateBox : function(box){
16087 this.setSize(box.width, box.height);
16088 this.setPagePosition(box.x, box.y);
16093 getResizeEl : function(){
16094 return this.resizeEl || this.el;
16098 getPositionEl : function(){
16099 return this.positionEl || this.el;
16103 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
16104 * This method fires the move event.
16105 * @param {Number} left The new left
16106 * @param {Number} top The new top
16107 * @returns {Roo.BoxComponent} this
16109 setPosition : function(x, y){
16112 if(!this.boxReady){
16115 var adj = this.adjustPosition(x, y);
16116 var ax = adj.x, ay = adj.y;
16118 var el = this.getPositionEl();
16119 if(ax !== undefined || ay !== undefined){
16120 if(ax !== undefined && ay !== undefined){
16121 el.setLeftTop(ax, ay);
16122 }else if(ax !== undefined){
16124 }else if(ay !== undefined){
16127 this.onPosition(ax, ay);
16128 this.fireEvent('move', this, ax, ay);
16134 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
16135 * This method fires the move event.
16136 * @param {Number} x The new x position
16137 * @param {Number} y The new y position
16138 * @returns {Roo.BoxComponent} this
16140 setPagePosition : function(x, y){
16143 if(!this.boxReady){
16146 if(x === undefined || y === undefined){ // cannot translate undefined points
16149 var p = this.el.translatePoints(x, y);
16150 this.setPosition(p.left, p.top);
16155 onRender : function(ct, position){
16156 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
16158 this.resizeEl = Roo.get(this.resizeEl);
16160 if(this.positionEl){
16161 this.positionEl = Roo.get(this.positionEl);
16166 afterRender : function(){
16167 Roo.BoxComponent.superclass.afterRender.call(this);
16168 this.boxReady = true;
16169 this.setSize(this.width, this.height);
16170 if(this.x || this.y){
16171 this.setPosition(this.x, this.y);
16173 if(this.pageX || this.pageY){
16174 this.setPagePosition(this.pageX, this.pageY);
16179 * Force the component's size to recalculate based on the underlying element's current height and width.
16180 * @returns {Roo.BoxComponent} this
16182 syncSize : function(){
16183 delete this.lastSize;
16184 this.setSize(this.el.getWidth(), this.el.getHeight());
16189 * Called after the component is resized, this method is empty by default but can be implemented by any
16190 * subclass that needs to perform custom logic after a resize occurs.
16191 * @param {Number} adjWidth The box-adjusted width that was set
16192 * @param {Number} adjHeight The box-adjusted height that was set
16193 * @param {Number} rawWidth The width that was originally specified
16194 * @param {Number} rawHeight The height that was originally specified
16196 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
16201 * Called after the component is moved, this method is empty by default but can be implemented by any
16202 * subclass that needs to perform custom logic after a move occurs.
16203 * @param {Number} x The new x position
16204 * @param {Number} y The new y position
16206 onPosition : function(x, y){
16211 adjustSize : function(w, h){
16212 if(this.autoWidth){
16215 if(this.autoHeight){
16218 return {width : w, height: h};
16222 adjustPosition : function(x, y){
16223 return {x : x, y: y};
16227 * Ext JS Library 1.1.1
16228 * Copyright(c) 2006-2007, Ext JS, LLC.
16230 * Originally Released Under LGPL - original licence link has changed is not relivant.
16233 * <script type="text/javascript">
16238 * @extends Roo.Element
16239 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
16240 * automatic maintaining of shadow/shim positions.
16241 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
16242 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
16243 * you can pass a string with a CSS class name. False turns off the shadow.
16244 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
16245 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
16246 * @cfg {String} cls CSS class to add to the element
16247 * @cfg {Number} zindex Starting z-index (defaults to 11000)
16248 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
16250 * @param {Object} config An object with config options.
16251 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
16254 Roo.Layer = function(config, existingEl){
16255 config = config || {};
16256 var dh = Roo.DomHelper;
16257 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
16259 this.dom = Roo.getDom(existingEl);
16262 var o = config.dh || {tag: "div", cls: "x-layer"};
16263 this.dom = dh.append(pel, o);
16266 this.addClass(config.cls);
16268 this.constrain = config.constrain !== false;
16269 this.visibilityMode = Roo.Element.VISIBILITY;
16271 this.id = this.dom.id = config.id;
16273 this.id = Roo.id(this.dom);
16275 this.zindex = config.zindex || this.getZIndex();
16276 this.position("absolute", this.zindex);
16278 this.shadowOffset = config.shadowOffset || 4;
16279 this.shadow = new Roo.Shadow({
16280 offset : this.shadowOffset,
16281 mode : config.shadow
16284 this.shadowOffset = 0;
16286 this.useShim = config.shim !== false && Roo.useShims;
16287 this.useDisplay = config.useDisplay;
16291 var supr = Roo.Element.prototype;
16293 // shims are shared among layer to keep from having 100 iframes
16296 Roo.extend(Roo.Layer, Roo.Element, {
16298 getZIndex : function(){
16299 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
16302 getShim : function(){
16309 var shim = shims.shift();
16311 shim = this.createShim();
16312 shim.enableDisplayMode('block');
16313 shim.dom.style.display = 'none';
16314 shim.dom.style.visibility = 'visible';
16316 var pn = this.dom.parentNode;
16317 if(shim.dom.parentNode != pn){
16318 pn.insertBefore(shim.dom, this.dom);
16320 shim.setStyle('z-index', this.getZIndex()-2);
16325 hideShim : function(){
16327 this.shim.setDisplayed(false);
16328 shims.push(this.shim);
16333 disableShadow : function(){
16335 this.shadowDisabled = true;
16336 this.shadow.hide();
16337 this.lastShadowOffset = this.shadowOffset;
16338 this.shadowOffset = 0;
16342 enableShadow : function(show){
16344 this.shadowDisabled = false;
16345 this.shadowOffset = this.lastShadowOffset;
16346 delete this.lastShadowOffset;
16354 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
16355 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
16356 sync : function(doShow){
16357 var sw = this.shadow;
16358 if(!this.updating && this.isVisible() && (sw || this.useShim)){
16359 var sh = this.getShim();
16361 var w = this.getWidth(),
16362 h = this.getHeight();
16364 var l = this.getLeft(true),
16365 t = this.getTop(true);
16367 if(sw && !this.shadowDisabled){
16368 if(doShow && !sw.isVisible()){
16371 sw.realign(l, t, w, h);
16377 // fit the shim behind the shadow, so it is shimmed too
16378 var a = sw.adjusts, s = sh.dom.style;
16379 s.left = (Math.min(l, l+a.l))+"px";
16380 s.top = (Math.min(t, t+a.t))+"px";
16381 s.width = (w+a.w)+"px";
16382 s.height = (h+a.h)+"px";
16389 sh.setLeftTop(l, t);
16396 destroy : function(){
16399 this.shadow.hide();
16401 this.removeAllListeners();
16402 var pn = this.dom.parentNode;
16404 pn.removeChild(this.dom);
16406 Roo.Element.uncache(this.id);
16409 remove : function(){
16414 beginUpdate : function(){
16415 this.updating = true;
16419 endUpdate : function(){
16420 this.updating = false;
16425 hideUnders : function(negOffset){
16427 this.shadow.hide();
16433 constrainXY : function(){
16434 if(this.constrain){
16435 var vw = Roo.lib.Dom.getViewWidth(),
16436 vh = Roo.lib.Dom.getViewHeight();
16437 var s = Roo.get(document).getScroll();
16439 var xy = this.getXY();
16440 var x = xy[0], y = xy[1];
16441 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
16442 // only move it if it needs it
16444 // first validate right/bottom
16445 if((x + w) > vw+s.left){
16446 x = vw - w - this.shadowOffset;
16449 if((y + h) > vh+s.top){
16450 y = vh - h - this.shadowOffset;
16453 // then make sure top/left isn't negative
16464 var ay = this.avoidY;
16465 if(y <= ay && (y+h) >= ay){
16471 supr.setXY.call(this, xy);
16477 isVisible : function(){
16478 return this.visible;
16482 showAction : function(){
16483 this.visible = true; // track visibility to prevent getStyle calls
16484 if(this.useDisplay === true){
16485 this.setDisplayed("");
16486 }else if(this.lastXY){
16487 supr.setXY.call(this, this.lastXY);
16488 }else if(this.lastLT){
16489 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
16494 hideAction : function(){
16495 this.visible = false;
16496 if(this.useDisplay === true){
16497 this.setDisplayed(false);
16499 this.setLeftTop(-10000,-10000);
16503 // overridden Element method
16504 setVisible : function(v, a, d, c, e){
16509 var cb = function(){
16514 }.createDelegate(this);
16515 supr.setVisible.call(this, true, true, d, cb, e);
16518 this.hideUnders(true);
16527 }.createDelegate(this);
16529 supr.setVisible.call(this, v, a, d, cb, e);
16538 storeXY : function(xy){
16539 delete this.lastLT;
16543 storeLeftTop : function(left, top){
16544 delete this.lastXY;
16545 this.lastLT = [left, top];
16549 beforeFx : function(){
16550 this.beforeAction();
16551 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
16555 afterFx : function(){
16556 Roo.Layer.superclass.afterFx.apply(this, arguments);
16557 this.sync(this.isVisible());
16561 beforeAction : function(){
16562 if(!this.updating && this.shadow){
16563 this.shadow.hide();
16567 // overridden Element method
16568 setLeft : function(left){
16569 this.storeLeftTop(left, this.getTop(true));
16570 supr.setLeft.apply(this, arguments);
16574 setTop : function(top){
16575 this.storeLeftTop(this.getLeft(true), top);
16576 supr.setTop.apply(this, arguments);
16580 setLeftTop : function(left, top){
16581 this.storeLeftTop(left, top);
16582 supr.setLeftTop.apply(this, arguments);
16586 setXY : function(xy, a, d, c, e){
16588 this.beforeAction();
16590 var cb = this.createCB(c);
16591 supr.setXY.call(this, xy, a, d, cb, e);
16598 createCB : function(c){
16609 // overridden Element method
16610 setX : function(x, a, d, c, e){
16611 this.setXY([x, this.getY()], a, d, c, e);
16614 // overridden Element method
16615 setY : function(y, a, d, c, e){
16616 this.setXY([this.getX(), y], a, d, c, e);
16619 // overridden Element method
16620 setSize : function(w, h, a, d, c, e){
16621 this.beforeAction();
16622 var cb = this.createCB(c);
16623 supr.setSize.call(this, w, h, a, d, cb, e);
16629 // overridden Element method
16630 setWidth : function(w, a, d, c, e){
16631 this.beforeAction();
16632 var cb = this.createCB(c);
16633 supr.setWidth.call(this, w, a, d, cb, e);
16639 // overridden Element method
16640 setHeight : function(h, a, d, c, e){
16641 this.beforeAction();
16642 var cb = this.createCB(c);
16643 supr.setHeight.call(this, h, a, d, cb, e);
16649 // overridden Element method
16650 setBounds : function(x, y, w, h, a, d, c, e){
16651 this.beforeAction();
16652 var cb = this.createCB(c);
16654 this.storeXY([x, y]);
16655 supr.setXY.call(this, [x, y]);
16656 supr.setSize.call(this, w, h, a, d, cb, e);
16659 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
16665 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
16666 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
16667 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
16668 * @param {Number} zindex The new z-index to set
16669 * @return {this} The Layer
16671 setZIndex : function(zindex){
16672 this.zindex = zindex;
16673 this.setStyle("z-index", zindex + 2);
16675 this.shadow.setZIndex(zindex + 1);
16678 this.shim.setStyle("z-index", zindex);
16683 * Original code for Roojs - LGPL
16684 * <script type="text/javascript">
16688 * @class Roo.XComponent
16689 * A delayed Element creator...
16690 * Or a way to group chunks of interface together.
16691 * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
16692 * used in conjunction with XComponent.build() it will create an instance of each element,
16693 * then call addxtype() to build the User interface.
16695 * Mypart.xyx = new Roo.XComponent({
16697 parent : 'Mypart.xyz', // empty == document.element.!!
16701 disabled : function() {}
16703 tree : function() { // return an tree of xtype declared components
16707 xtype : 'NestedLayoutPanel',
16714 * It can be used to build a big heiracy, with parent etc.
16715 * or you can just use this to render a single compoent to a dom element
16716 * MYPART.render(Roo.Element | String(id) | dom_element )
16723 * Roo is designed primarily as a single page application, so the UI build for a standard interface will
16724 * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
16726 * Each sub module is expected to have a parent pointing to the class name of it's parent module.
16728 * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
16729 * - if mulitple topModules exist, the last one is defined as the top module.
16733 * When the top level or multiple modules are to embedded into a existing HTML page,
16734 * the parent element can container '#id' of the element where the module will be drawn.
16738 * Unlike classic Roo, the bootstrap tends not to be used as a single page.
16739 * it relies more on a include mechanism, where sub modules are included into an outer page.
16740 * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
16742 * Bootstrap Roo Included elements
16744 * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
16745 * hence confusing the component builder as it thinks there are multiple top level elements.
16747 * String Over-ride & Translations
16749 * Our builder application writes all the strings as _strings and _named_strings. This is to enable the translation of elements,
16750 * and also the 'overlaying of string values - needed when different versions of the same application with different text content
16751 * are needed. @see Roo.XComponent.overlayString
16755 * @extends Roo.util.Observable
16757 * @param cfg {Object} configuration of component
16760 Roo.XComponent = function(cfg) {
16761 Roo.apply(this, cfg);
16765 * Fires when this the componnt is built
16766 * @param {Roo.XComponent} c the component
16771 this.region = this.region || 'center'; // default..
16772 Roo.XComponent.register(this);
16773 this.modules = false;
16774 this.el = false; // where the layout goes..
16778 Roo.extend(Roo.XComponent, Roo.util.Observable, {
16781 * The created element (with Roo.factory())
16782 * @type {Roo.Layout}
16788 * for BC - use el in new code
16789 * @type {Roo.Layout}
16795 * for BC - use el in new code
16796 * @type {Roo.Layout}
16801 * @cfg {Function|boolean} disabled
16802 * If this module is disabled by some rule, return true from the funtion
16807 * @cfg {String} parent
16808 * Name of parent element which it get xtype added to..
16813 * @cfg {String} order
16814 * Used to set the order in which elements are created (usefull for multiple tabs)
16819 * @cfg {String} name
16820 * String to display while loading.
16824 * @cfg {String} region
16825 * Region to render component to (defaults to center)
16830 * @cfg {Array} items
16831 * A single item array - the first element is the root of the tree..
16832 * It's done this way to stay compatible with the Xtype system...
16838 * The method that retuns the tree of parts that make up this compoennt
16845 * render element to dom or tree
16846 * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
16849 render : function(el)
16853 var hp = this.parent ? 1 : 0;
16854 Roo.debug && Roo.log(this);
16856 var tree = this._tree ? this._tree() : this.tree();
16859 if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
16860 // if parent is a '#.....' string, then let's use that..
16861 var ename = this.parent.substr(1);
16862 this.parent = false;
16863 Roo.debug && Roo.log(ename);
16865 case 'bootstrap-body':
16866 if (typeof(tree.el) != 'undefined' && tree.el == document.body) {
16867 // this is the BorderLayout standard?
16868 this.parent = { el : true };
16871 if (["Nest", "Content", "Grid", "Tree"].indexOf(tree.xtype) > -1) {
16872 // need to insert stuff...
16874 el : new Roo.bootstrap.layout.Border({
16875 el : document.body,
16881 tabPosition: 'top',
16882 //resizeTabs: true,
16883 alwaysShowTabs: true,
16893 if (typeof(Roo.bootstrap.Body) != 'undefined' ) {
16894 this.parent = { el : new Roo.bootstrap.Body() };
16895 Roo.debug && Roo.log("setting el to doc body");
16898 throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
16902 this.parent = { el : true};
16905 el = Roo.get(ename);
16906 if (typeof(Roo.bootstrap) != 'undefined' && tree['|xns'] == 'Roo.bootstrap') {
16907 this.parent = { el : true};
16914 if (!el && !this.parent) {
16915 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
16920 Roo.debug && Roo.log("EL:");
16921 Roo.debug && Roo.log(el);
16922 Roo.debug && Roo.log("this.parent.el:");
16923 Roo.debug && Roo.log(this.parent.el);
16926 // altertive root elements ??? - we need a better way to indicate these.
16927 var is_alt = Roo.XComponent.is_alt ||
16928 (typeof(tree.el) != 'undefined' && tree.el == document.body) ||
16929 (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
16930 (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
16934 if (!this.parent && is_alt) {
16935 //el = Roo.get(document.body);
16936 this.parent = { el : true };
16941 if (!this.parent) {
16943 Roo.debug && Roo.log("no parent - creating one");
16945 el = el ? Roo.get(el) : false;
16947 if (typeof(Roo.BorderLayout) == 'undefined' ) {
16950 el : new Roo.bootstrap.layout.Border({
16951 el: el || document.body,
16957 tabPosition: 'top',
16958 //resizeTabs: true,
16959 alwaysShowTabs: false,
16962 overflow: 'visible'
16968 // it's a top level one..
16970 el : new Roo.BorderLayout(el || document.body, {
16975 tabPosition: 'top',
16976 //resizeTabs: true,
16977 alwaysShowTabs: el && hp? false : true,
16978 hideTabs: el || !hp ? true : false,
16986 if (!this.parent.el) {
16987 // probably an old style ctor, which has been disabled.
16991 // The 'tree' method is '_tree now'
16993 tree.region = tree.region || this.region;
16994 var is_body = false;
16995 if (this.parent.el === true) {
16996 // bootstrap... - body..
17000 this.parent.el = Roo.factory(tree);
17004 this.el = this.parent.el.addxtype(tree, undefined, is_body);
17005 this.fireEvent('built', this);
17007 this.panel = this.el;
17008 this.layout = this.panel.layout;
17009 this.parentLayout = this.parent.layout || false;
17015 Roo.apply(Roo.XComponent, {
17017 * @property hideProgress
17018 * true to disable the building progress bar.. usefull on single page renders.
17021 hideProgress : false,
17023 * @property buildCompleted
17024 * True when the builder has completed building the interface.
17027 buildCompleted : false,
17030 * @property topModule
17031 * the upper most module - uses document.element as it's constructor.
17038 * @property modules
17039 * array of modules to be created by registration system.
17040 * @type {Array} of Roo.XComponent
17045 * @property elmodules
17046 * array of modules to be created by which use #ID
17047 * @type {Array} of Roo.XComponent
17054 * Is an alternative Root - normally used by bootstrap or other systems,
17055 * where the top element in the tree can wrap 'body'
17056 * @type {boolean} (default false)
17061 * @property build_from_html
17062 * Build elements from html - used by bootstrap HTML stuff
17063 * - this is cleared after build is completed
17064 * @type {boolean} (default false)
17067 build_from_html : false,
17069 * Register components to be built later.
17071 * This solves the following issues
17072 * - Building is not done on page load, but after an authentication process has occured.
17073 * - Interface elements are registered on page load
17074 * - Parent Interface elements may not be loaded before child, so this handles that..
17081 module : 'Pman.Tab.projectMgr',
17083 parent : 'Pman.layout',
17084 disabled : false, // or use a function..
17087 * * @param {Object} details about module
17089 register : function(obj) {
17091 Roo.XComponent.event.fireEvent('register', obj);
17092 switch(typeof(obj.disabled) ) {
17098 if ( obj.disabled() ) {
17104 if (obj.disabled || obj.region == '#disabled') {
17110 this.modules.push(obj);
17114 * convert a string to an object..
17115 * eg. 'AAA.BBB' -> finds AAA.BBB
17119 toObject : function(str)
17121 if (!str || typeof(str) == 'object') {
17124 if (str.substring(0,1) == '#') {
17128 var ar = str.split('.');
17133 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
17135 throw "Module not found : " + str;
17139 throw "Module not found : " + str;
17141 Roo.each(ar, function(e) {
17142 if (typeof(o[e]) == 'undefined') {
17143 throw "Module not found : " + str;
17154 * move modules into their correct place in the tree..
17157 preBuild : function ()
17160 Roo.each(this.modules , function (obj)
17162 Roo.XComponent.event.fireEvent('beforebuild', obj);
17164 var opar = obj.parent;
17166 obj.parent = this.toObject(opar);
17168 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
17173 Roo.debug && Roo.log("GOT top level module");
17174 Roo.debug && Roo.log(obj);
17175 obj.modules = new Roo.util.MixedCollection(false,
17176 function(o) { return o.order + '' }
17178 this.topModule = obj;
17181 // parent is a string (usually a dom element name..)
17182 if (typeof(obj.parent) == 'string') {
17183 this.elmodules.push(obj);
17186 if (obj.parent.constructor != Roo.XComponent) {
17187 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
17189 if (!obj.parent.modules) {
17190 obj.parent.modules = new Roo.util.MixedCollection(false,
17191 function(o) { return o.order + '' }
17194 if (obj.parent.disabled) {
17195 obj.disabled = true;
17197 obj.parent.modules.add(obj);
17202 * make a list of modules to build.
17203 * @return {Array} list of modules.
17206 buildOrder : function()
17209 var cmp = function(a,b) {
17210 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
17212 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
17213 throw "No top level modules to build";
17216 // make a flat list in order of modules to build.
17217 var mods = this.topModule ? [ this.topModule ] : [];
17220 // elmodules (is a list of DOM based modules )
17221 Roo.each(this.elmodules, function(e) {
17223 if (!this.topModule &&
17224 typeof(e.parent) == 'string' &&
17225 e.parent.substring(0,1) == '#' &&
17226 Roo.get(e.parent.substr(1))
17229 _this.topModule = e;
17235 // add modules to their parents..
17236 var addMod = function(m) {
17237 Roo.debug && Roo.log("build Order: add: " + m.name);
17240 if (m.modules && !m.disabled) {
17241 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
17242 m.modules.keySort('ASC', cmp );
17243 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
17245 m.modules.each(addMod);
17247 Roo.debug && Roo.log("build Order: no child modules");
17249 // not sure if this is used any more..
17251 m.finalize.name = m.name + " (clean up) ";
17252 mods.push(m.finalize);
17256 if (this.topModule && this.topModule.modules) {
17257 this.topModule.modules.keySort('ASC', cmp );
17258 this.topModule.modules.each(addMod);
17264 * Build the registered modules.
17265 * @param {Object} parent element.
17266 * @param {Function} optional method to call after module has been added.
17270 build : function(opts)
17273 if (typeof(opts) != 'undefined') {
17274 Roo.apply(this,opts);
17278 var mods = this.buildOrder();
17280 //this.allmods = mods;
17281 //Roo.debug && Roo.log(mods);
17283 if (!mods.length) { // should not happen
17284 throw "NO modules!!!";
17288 var msg = "Building Interface...";
17289 // flash it up as modal - so we store the mask!?
17290 if (!this.hideProgress && Roo.MessageBox) {
17291 Roo.MessageBox.show({ title: 'loading' });
17292 Roo.MessageBox.show({
17293 title: "Please wait...",
17303 var total = mods.length;
17306 var progressRun = function() {
17307 if (!mods.length) {
17308 Roo.debug && Roo.log('hide?');
17309 if (!this.hideProgress && Roo.MessageBox) {
17310 Roo.MessageBox.hide();
17312 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
17314 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
17320 var m = mods.shift();
17323 Roo.debug && Roo.log(m);
17324 // not sure if this is supported any more.. - modules that are are just function
17325 if (typeof(m) == 'function') {
17327 return progressRun.defer(10, _this);
17331 msg = "Building Interface " + (total - mods.length) +
17333 (m.name ? (' - ' + m.name) : '');
17334 Roo.debug && Roo.log(msg);
17335 if (!_this.hideProgress && Roo.MessageBox) {
17336 Roo.MessageBox.updateProgress( (total - mods.length)/total, msg );
17340 // is the module disabled?
17341 var disabled = (typeof(m.disabled) == 'function') ?
17342 m.disabled.call(m.module.disabled) : m.disabled;
17346 return progressRun(); // we do not update the display!
17354 // it's 10 on top level, and 1 on others??? why...
17355 return progressRun.defer(10, _this);
17358 progressRun.defer(1, _this);
17364 * Overlay a set of modified strings onto a component
17365 * This is dependant on our builder exporting the strings and 'named strings' elements.
17367 * @param {Object} element to overlay on - eg. Pman.Dialog.Login
17368 * @param {Object} associative array of 'named' string and it's new value.
17371 overlayStrings : function( component, strings )
17373 if (typeof(component['_named_strings']) == 'undefined') {
17374 throw "ERROR: component does not have _named_strings";
17376 for ( var k in strings ) {
17377 var md = typeof(component['_named_strings'][k]) == 'undefined' ? false : component['_named_strings'][k];
17378 if (md !== false) {
17379 component['_strings'][md] = strings[k];
17381 Roo.log('could not find named string: ' + k + ' in');
17382 Roo.log(component);
17397 * wrapper for event.on - aliased later..
17398 * Typically use to register a event handler for register:
17400 * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
17409 Roo.XComponent.event = new Roo.util.Observable({
17413 * Fires when an Component is registered,
17414 * set the disable property on the Component to stop registration.
17415 * @param {Roo.XComponent} c the component being registerd.
17420 * @event beforebuild
17421 * Fires before each Component is built
17422 * can be used to apply permissions.
17423 * @param {Roo.XComponent} c the component being registerd.
17426 'beforebuild' : true,
17428 * @event buildcomplete
17429 * Fires on the top level element when all elements have been built
17430 * @param {Roo.XComponent} the top level component.
17432 'buildcomplete' : true
17437 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event);
17440 * marked - a markdown parser
17441 * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
17442 * https://github.com/chjj/marked
17448 * Roo.Markdown - is a very crude wrapper around marked..
17452 * alert( Roo.Markdown.toHtml("Markdown *rocks*.") );
17454 * Note: move the sample code to the bottom of this
17455 * file before uncommenting it.
17460 Roo.Markdown.toHtml = function(text) {
17462 var c = new Roo.Markdown.marked.setOptions({
17463 renderer: new Roo.Markdown.marked.Renderer(),
17474 text = text.replace(/\\\n/g,' ');
17475 return Roo.Markdown.marked(text);
17480 // Wraps all "globals" so that the only thing
17481 // exposed is makeHtml().
17487 * eval:var:unescape
17495 var escape = function (html, encode) {
17497 .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&')
17498 .replace(/</g, '<')
17499 .replace(/>/g, '>')
17500 .replace(/"/g, '"')
17501 .replace(/'/g, ''');
17504 var unescape = function (html) {
17505 // explicitly match decimal, hex, and named HTML entities
17506 return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
17507 n = n.toLowerCase();
17508 if (n === 'colon') { return ':'; }
17509 if (n.charAt(0) === '#') {
17510 return n.charAt(1) === 'x'
17511 ? String.fromCharCode(parseInt(n.substring(2), 16))
17512 : String.fromCharCode(+n.substring(1));
17518 var replace = function (regex, opt) {
17519 regex = regex.source;
17521 return function self(name, val) {
17522 if (!name) { return new RegExp(regex, opt); }
17523 val = val.source || val;
17524 val = val.replace(/(^|[^\[])\^/g, '$1');
17525 regex = regex.replace(name, val);
17534 var noop = function () {}
17540 var merge = function (obj) {
17545 for (; i < arguments.length; i++) {
17546 target = arguments[i];
17547 for (key in target) {
17548 if (Object.prototype.hasOwnProperty.call(target, key)) {
17549 obj[key] = target[key];
17559 * Block-Level Grammar
17567 code: /^( {4}[^\n]+\n*)+/,
17569 hr: /^( *[-*_]){3,} *(?:\n+|$)/,
17570 heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
17572 lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
17573 blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
17574 list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
17575 html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
17576 def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
17578 paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
17582 block.bullet = /(?:[*+-]|\d+\.)/;
17583 block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
17584 block.item = replace(block.item, 'gm')
17585 (/bull/g, block.bullet)
17588 block.list = replace(block.list)
17589 (/bull/g, block.bullet)
17590 ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
17591 ('def', '\\n+(?=' + block.def.source + ')')
17594 block.blockquote = replace(block.blockquote)
17598 block._tag = '(?!(?:'
17599 + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
17600 + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
17601 + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
17603 block.html = replace(block.html)
17604 ('comment', /<!--[\s\S]*?-->/)
17605 ('closed', /<(tag)[\s\S]+?<\/\1>/)
17606 ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
17607 (/tag/g, block._tag)
17610 block.paragraph = replace(block.paragraph)
17612 ('heading', block.heading)
17613 ('lheading', block.lheading)
17614 ('blockquote', block.blockquote)
17615 ('tag', '<' + block._tag)
17620 * Normal Block Grammar
17623 block.normal = merge({}, block);
17626 * GFM Block Grammar
17629 block.gfm = merge({}, block.normal, {
17630 fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,
17632 heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
17635 block.gfm.paragraph = replace(block.paragraph)
17637 + block.gfm.fences.source.replace('\\1', '\\2') + '|'
17638 + block.list.source.replace('\\1', '\\3') + '|')
17642 * GFM + Tables Block Grammar
17645 block.tables = merge({}, block.gfm, {
17646 nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
17647 table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
17654 var Lexer = function (options) {
17656 this.tokens.links = {};
17657 this.options = options || marked.defaults;
17658 this.rules = block.normal;
17660 if (this.options.gfm) {
17661 if (this.options.tables) {
17662 this.rules = block.tables;
17664 this.rules = block.gfm;
17670 * Expose Block Rules
17673 Lexer.rules = block;
17676 * Static Lex Method
17679 Lexer.lex = function(src, options) {
17680 var lexer = new Lexer(options);
17681 return lexer.lex(src);
17688 Lexer.prototype.lex = function(src) {
17690 .replace(/\r\n|\r/g, '\n')
17691 .replace(/\t/g, ' ')
17692 .replace(/\u00a0/g, ' ')
17693 .replace(/\u2424/g, '\n');
17695 return this.token(src, true);
17702 Lexer.prototype.token = function(src, top, bq) {
17703 var src = src.replace(/^ +$/gm, '')
17716 if (cap = this.rules.newline.exec(src)) {
17717 src = src.substring(cap[0].length);
17718 if (cap[0].length > 1) {
17726 if (cap = this.rules.code.exec(src)) {
17727 src = src.substring(cap[0].length);
17728 cap = cap[0].replace(/^ {4}/gm, '');
17731 text: !this.options.pedantic
17732 ? cap.replace(/\n+$/, '')
17739 if (cap = this.rules.fences.exec(src)) {
17740 src = src.substring(cap[0].length);
17750 if (cap = this.rules.heading.exec(src)) {
17751 src = src.substring(cap[0].length);
17754 depth: cap[1].length,
17760 // table no leading pipe (gfm)
17761 if (top && (cap = this.rules.nptable.exec(src))) {
17762 src = src.substring(cap[0].length);
17766 header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
17767 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
17768 cells: cap[3].replace(/\n$/, '').split('\n')
17771 for (i = 0; i < item.align.length; i++) {
17772 if (/^ *-+: *$/.test(item.align[i])) {
17773 item.align[i] = 'right';
17774 } else if (/^ *:-+: *$/.test(item.align[i])) {
17775 item.align[i] = 'center';
17776 } else if (/^ *:-+ *$/.test(item.align[i])) {
17777 item.align[i] = 'left';
17779 item.align[i] = null;
17783 for (i = 0; i < item.cells.length; i++) {
17784 item.cells[i] = item.cells[i].split(/ *\| */);
17787 this.tokens.push(item);
17793 if (cap = this.rules.lheading.exec(src)) {
17794 src = src.substring(cap[0].length);
17797 depth: cap[2] === '=' ? 1 : 2,
17804 if (cap = this.rules.hr.exec(src)) {
17805 src = src.substring(cap[0].length);
17813 if (cap = this.rules.blockquote.exec(src)) {
17814 src = src.substring(cap[0].length);
17817 type: 'blockquote_start'
17820 cap = cap[0].replace(/^ *> ?/gm, '');
17822 // Pass `top` to keep the current
17823 // "toplevel" state. This is exactly
17824 // how markdown.pl works.
17825 this.token(cap, top, true);
17828 type: 'blockquote_end'
17835 if (cap = this.rules.list.exec(src)) {
17836 src = src.substring(cap[0].length);
17840 type: 'list_start',
17841 ordered: bull.length > 1
17844 // Get each top-level item.
17845 cap = cap[0].match(this.rules.item);
17851 for (; i < l; i++) {
17854 // Remove the list item's bullet
17855 // so it is seen as the next token.
17856 space = item.length;
17857 item = item.replace(/^ *([*+-]|\d+\.) +/, '');
17859 // Outdent whatever the
17860 // list item contains. Hacky.
17861 if (~item.indexOf('\n ')) {
17862 space -= item.length;
17863 item = !this.options.pedantic
17864 ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
17865 : item.replace(/^ {1,4}/gm, '');
17868 // Determine whether the next list item belongs here.
17869 // Backpedal if it does not belong in this list.
17870 if (this.options.smartLists && i !== l - 1) {
17871 b = block.bullet.exec(cap[i + 1])[0];
17872 if (bull !== b && !(bull.length > 1 && b.length > 1)) {
17873 src = cap.slice(i + 1).join('\n') + src;
17878 // Determine whether item is loose or not.
17879 // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
17880 // for discount behavior.
17881 loose = next || /\n\n(?!\s*$)/.test(item);
17883 next = item.charAt(item.length - 1) === '\n';
17884 if (!loose) { loose = next; }
17889 ? 'loose_item_start'
17890 : 'list_item_start'
17894 this.token(item, false, bq);
17897 type: 'list_item_end'
17909 if (cap = this.rules.html.exec(src)) {
17910 src = src.substring(cap[0].length);
17912 type: this.options.sanitize
17915 pre: !this.options.sanitizer
17916 && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
17923 if ((!bq && top) && (cap = this.rules.def.exec(src))) {
17924 src = src.substring(cap[0].length);
17925 this.tokens.links[cap[1].toLowerCase()] = {
17933 if (top && (cap = this.rules.table.exec(src))) {
17934 src = src.substring(cap[0].length);
17938 header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
17939 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
17940 cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
17943 for (i = 0; i < item.align.length; i++) {
17944 if (/^ *-+: *$/.test(item.align[i])) {
17945 item.align[i] = 'right';
17946 } else if (/^ *:-+: *$/.test(item.align[i])) {
17947 item.align[i] = 'center';
17948 } else if (/^ *:-+ *$/.test(item.align[i])) {
17949 item.align[i] = 'left';
17951 item.align[i] = null;
17955 for (i = 0; i < item.cells.length; i++) {
17956 item.cells[i] = item.cells[i]
17957 .replace(/^ *\| *| *\| *$/g, '')
17961 this.tokens.push(item);
17966 // top-level paragraph
17967 if (top && (cap = this.rules.paragraph.exec(src))) {
17968 src = src.substring(cap[0].length);
17971 text: cap[1].charAt(cap[1].length - 1) === '\n'
17972 ? cap[1].slice(0, -1)
17979 if (cap = this.rules.text.exec(src)) {
17980 // Top-level should never reach here.
17981 src = src.substring(cap[0].length);
17991 Error('Infinite loop on byte: ' + src.charCodeAt(0));
17995 return this.tokens;
17999 * Inline-Level Grammar
18003 escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
18004 autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
18006 tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
18007 link: /^!?\[(inside)\]\(href\)/,
18008 reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
18009 nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
18010 strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
18011 em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
18012 code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
18013 br: /^ {2,}\n(?!\s*$)/,
18015 text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
18018 inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
18019 inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
18021 inline.link = replace(inline.link)
18022 ('inside', inline._inside)
18023 ('href', inline._href)
18026 inline.reflink = replace(inline.reflink)
18027 ('inside', inline._inside)
18031 * Normal Inline Grammar
18034 inline.normal = merge({}, inline);
18037 * Pedantic Inline Grammar
18040 inline.pedantic = merge({}, inline.normal, {
18041 strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
18042 em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
18046 * GFM Inline Grammar
18049 inline.gfm = merge({}, inline.normal, {
18050 escape: replace(inline.escape)('])', '~|])')(),
18051 url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
18052 del: /^~~(?=\S)([\s\S]*?\S)~~/,
18053 text: replace(inline.text)
18055 ('|', '|https?://|')
18060 * GFM + Line Breaks Inline Grammar
18063 inline.breaks = merge({}, inline.gfm, {
18064 br: replace(inline.br)('{2,}', '*')(),
18065 text: replace(inline.gfm.text)('{2,}', '*')()
18069 * Inline Lexer & Compiler
18072 var InlineLexer = function (links, options) {
18073 this.options = options || marked.defaults;
18074 this.links = links;
18075 this.rules = inline.normal;
18076 this.renderer = this.options.renderer || new Renderer;
18077 this.renderer.options = this.options;
18081 Error('Tokens array requires a `links` property.');
18084 if (this.options.gfm) {
18085 if (this.options.breaks) {
18086 this.rules = inline.breaks;
18088 this.rules = inline.gfm;
18090 } else if (this.options.pedantic) {
18091 this.rules = inline.pedantic;
18096 * Expose Inline Rules
18099 InlineLexer.rules = inline;
18102 * Static Lexing/Compiling Method
18105 InlineLexer.output = function(src, links, options) {
18106 var inline = new InlineLexer(links, options);
18107 return inline.output(src);
18114 InlineLexer.prototype.output = function(src) {
18123 if (cap = this.rules.escape.exec(src)) {
18124 src = src.substring(cap[0].length);
18130 if (cap = this.rules.autolink.exec(src)) {
18131 src = src.substring(cap[0].length);
18132 if (cap[2] === '@') {
18133 text = cap[1].charAt(6) === ':'
18134 ? this.mangle(cap[1].substring(7))
18135 : this.mangle(cap[1]);
18136 href = this.mangle('mailto:') + text;
18138 text = escape(cap[1]);
18141 out += this.renderer.link(href, null, text);
18146 if (!this.inLink && (cap = this.rules.url.exec(src))) {
18147 src = src.substring(cap[0].length);
18148 text = escape(cap[1]);
18150 out += this.renderer.link(href, null, text);
18155 if (cap = this.rules.tag.exec(src)) {
18156 if (!this.inLink && /^<a /i.test(cap[0])) {
18157 this.inLink = true;
18158 } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
18159 this.inLink = false;
18161 src = src.substring(cap[0].length);
18162 out += this.options.sanitize
18163 ? this.options.sanitizer
18164 ? this.options.sanitizer(cap[0])
18171 if (cap = this.rules.link.exec(src)) {
18172 src = src.substring(cap[0].length);
18173 this.inLink = true;
18174 out += this.outputLink(cap, {
18178 this.inLink = false;
18183 if ((cap = this.rules.reflink.exec(src))
18184 || (cap = this.rules.nolink.exec(src))) {
18185 src = src.substring(cap[0].length);
18186 link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
18187 link = this.links[link.toLowerCase()];
18188 if (!link || !link.href) {
18189 out += cap[0].charAt(0);
18190 src = cap[0].substring(1) + src;
18193 this.inLink = true;
18194 out += this.outputLink(cap, link);
18195 this.inLink = false;
18200 if (cap = this.rules.strong.exec(src)) {
18201 src = src.substring(cap[0].length);
18202 out += this.renderer.strong(this.output(cap[2] || cap[1]));
18207 if (cap = this.rules.em.exec(src)) {
18208 src = src.substring(cap[0].length);
18209 out += this.renderer.em(this.output(cap[2] || cap[1]));
18214 if (cap = this.rules.code.exec(src)) {
18215 src = src.substring(cap[0].length);
18216 out += this.renderer.codespan(escape(cap[2], true));
18221 if (cap = this.rules.br.exec(src)) {
18222 src = src.substring(cap[0].length);
18223 out += this.renderer.br();
18228 if (cap = this.rules.del.exec(src)) {
18229 src = src.substring(cap[0].length);
18230 out += this.renderer.del(this.output(cap[1]));
18235 if (cap = this.rules.text.exec(src)) {
18236 src = src.substring(cap[0].length);
18237 out += this.renderer.text(escape(this.smartypants(cap[0])));
18243 Error('Infinite loop on byte: ' + src.charCodeAt(0));
18254 InlineLexer.prototype.outputLink = function(cap, link) {
18255 var href = escape(link.href)
18256 , title = link.title ? escape(link.title) : null;
18258 return cap[0].charAt(0) !== '!'
18259 ? this.renderer.link(href, title, this.output(cap[1]))
18260 : this.renderer.image(href, title, escape(cap[1]));
18264 * Smartypants Transformations
18267 InlineLexer.prototype.smartypants = function(text) {
18268 if (!this.options.smartypants) { return text; }
18271 .replace(/---/g, '\u2014')
18273 .replace(/--/g, '\u2013')
18275 .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
18276 // closing singles & apostrophes
18277 .replace(/'/g, '\u2019')
18279 .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
18281 .replace(/"/g, '\u201d')
18283 .replace(/\.{3}/g, '\u2026');
18290 InlineLexer.prototype.mangle = function(text) {
18291 if (!this.options.mangle) { return text; }
18297 for (; i < l; i++) {
18298 ch = text.charCodeAt(i);
18299 if (Math.random() > 0.5) {
18300 ch = 'x' + ch.toString(16);
18302 out += '&#' + ch + ';';
18313 * eval:var:Renderer
18316 var Renderer = function (options) {
18317 this.options = options || {};
18320 Renderer.prototype.code = function(code, lang, escaped) {
18321 if (this.options.highlight) {
18322 var out = this.options.highlight(code, lang);
18323 if (out != null && out !== code) {
18328 // hack!!! - it's already escapeD?
18333 return '<pre><code>'
18334 + (escaped ? code : escape(code, true))
18335 + '\n</code></pre>';
18338 return '<pre><code class="'
18339 + this.options.langPrefix
18340 + escape(lang, true)
18342 + (escaped ? code : escape(code, true))
18343 + '\n</code></pre>\n';
18346 Renderer.prototype.blockquote = function(quote) {
18347 return '<blockquote>\n' + quote + '</blockquote>\n';
18350 Renderer.prototype.html = function(html) {
18354 Renderer.prototype.heading = function(text, level, raw) {
18358 + this.options.headerPrefix
18359 + raw.toLowerCase().replace(/[^\w]+/g, '-')
18367 Renderer.prototype.hr = function() {
18368 return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
18371 Renderer.prototype.list = function(body, ordered) {
18372 var type = ordered ? 'ol' : 'ul';
18373 return '<' + type + '>\n' + body + '</' + type + '>\n';
18376 Renderer.prototype.listitem = function(text) {
18377 return '<li>' + text + '</li>\n';
18380 Renderer.prototype.paragraph = function(text) {
18381 return '<p>' + text + '</p>\n';
18384 Renderer.prototype.table = function(header, body) {
18385 return '<table class="table table-striped">\n'
18395 Renderer.prototype.tablerow = function(content) {
18396 return '<tr>\n' + content + '</tr>\n';
18399 Renderer.prototype.tablecell = function(content, flags) {
18400 var type = flags.header ? 'th' : 'td';
18401 var tag = flags.align
18402 ? '<' + type + ' style="text-align:' + flags.align + '">'
18403 : '<' + type + '>';
18404 return tag + content + '</' + type + '>\n';
18407 // span level renderer
18408 Renderer.prototype.strong = function(text) {
18409 return '<strong>' + text + '</strong>';
18412 Renderer.prototype.em = function(text) {
18413 return '<em>' + text + '</em>';
18416 Renderer.prototype.codespan = function(text) {
18417 return '<code>' + text + '</code>';
18420 Renderer.prototype.br = function() {
18421 return this.options.xhtml ? '<br/>' : '<br>';
18424 Renderer.prototype.del = function(text) {
18425 return '<del>' + text + '</del>';
18428 Renderer.prototype.link = function(href, title, text) {
18429 if (this.options.sanitize) {
18431 var prot = decodeURIComponent(unescape(href))
18432 .replace(/[^\w:]/g, '')
18437 if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) {
18441 var out = '<a href="' + href + '"';
18443 out += ' title="' + title + '"';
18445 out += '>' + text + '</a>';
18449 Renderer.prototype.image = function(href, title, text) {
18450 var out = '<img src="' + href + '" alt="' + text + '"';
18452 out += ' title="' + title + '"';
18454 out += this.options.xhtml ? '/>' : '>';
18458 Renderer.prototype.text = function(text) {
18463 * Parsing & Compiling
18469 var Parser= function (options) {
18472 this.options = options || marked.defaults;
18473 this.options.renderer = this.options.renderer || new Renderer;
18474 this.renderer = this.options.renderer;
18475 this.renderer.options = this.options;
18479 * Static Parse Method
18482 Parser.parse = function(src, options, renderer) {
18483 var parser = new Parser(options, renderer);
18484 return parser.parse(src);
18491 Parser.prototype.parse = function(src) {
18492 this.inline = new InlineLexer(src.links, this.options, this.renderer);
18493 this.tokens = src.reverse();
18496 while (this.next()) {
18507 Parser.prototype.next = function() {
18508 return this.token = this.tokens.pop();
18512 * Preview Next Token
18515 Parser.prototype.peek = function() {
18516 return this.tokens[this.tokens.length - 1] || 0;
18520 * Parse Text Tokens
18523 Parser.prototype.parseText = function() {
18524 var body = this.token.text;
18526 while (this.peek().type === 'text') {
18527 body += '\n' + this.next().text;
18530 return this.inline.output(body);
18534 * Parse Current Token
18537 Parser.prototype.tok = function() {
18538 switch (this.token.type) {
18543 return this.renderer.hr();
18546 return this.renderer.heading(
18547 this.inline.output(this.token.text),
18552 return this.renderer.code(this.token.text,
18554 this.token.escaped);
18567 for (i = 0; i < this.token.header.length; i++) {
18568 flags = { header: true, align: this.token.align[i] };
18569 cell += this.renderer.tablecell(
18570 this.inline.output(this.token.header[i]),
18571 { header: true, align: this.token.align[i] }
18574 header += this.renderer.tablerow(cell);
18576 for (i = 0; i < this.token.cells.length; i++) {
18577 row = this.token.cells[i];
18580 for (j = 0; j < row.length; j++) {
18581 cell += this.renderer.tablecell(
18582 this.inline.output(row[j]),
18583 { header: false, align: this.token.align[j] }
18587 body += this.renderer.tablerow(cell);
18589 return this.renderer.table(header, body);
18591 case 'blockquote_start': {
18594 while (this.next().type !== 'blockquote_end') {
18595 body += this.tok();
18598 return this.renderer.blockquote(body);
18600 case 'list_start': {
18602 , ordered = this.token.ordered;
18604 while (this.next().type !== 'list_end') {
18605 body += this.tok();
18608 return this.renderer.list(body, ordered);
18610 case 'list_item_start': {
18613 while (this.next().type !== 'list_item_end') {
18614 body += this.token.type === 'text'
18619 return this.renderer.listitem(body);
18621 case 'loose_item_start': {
18624 while (this.next().type !== 'list_item_end') {
18625 body += this.tok();
18628 return this.renderer.listitem(body);
18631 var html = !this.token.pre && !this.options.pedantic
18632 ? this.inline.output(this.token.text)
18634 return this.renderer.html(html);
18636 case 'paragraph': {
18637 return this.renderer.paragraph(this.inline.output(this.token.text));
18640 return this.renderer.paragraph(this.parseText());
18652 var marked = function (src, opt, callback) {
18653 if (callback || typeof opt === 'function') {
18659 opt = merge({}, marked.defaults, opt || {});
18661 var highlight = opt.highlight
18667 tokens = Lexer.lex(src, opt)
18669 return callback(e);
18672 pending = tokens.length;
18676 var done = function(err) {
18678 opt.highlight = highlight;
18679 return callback(err);
18685 out = Parser.parse(tokens, opt);
18690 opt.highlight = highlight;
18694 : callback(null, out);
18697 if (!highlight || highlight.length < 3) {
18701 delete opt.highlight;
18703 if (!pending) { return done(); }
18705 for (; i < tokens.length; i++) {
18707 if (token.type !== 'code') {
18708 return --pending || done();
18710 return highlight(token.text, token.lang, function(err, code) {
18711 if (err) { return done(err); }
18712 if (code == null || code === token.text) {
18713 return --pending || done();
18716 token.escaped = true;
18717 --pending || done();
18725 if (opt) { opt = merge({}, marked.defaults, opt); }
18726 return Parser.parse(Lexer.lex(src, opt), opt);
18728 e.message += '\nPlease report this to https://github.com/chjj/marked.';
18729 if ((opt || marked.defaults).silent) {
18730 return '<p>An error occured:</p><pre>'
18731 + escape(e.message + '', true)
18743 marked.setOptions = function(opt) {
18744 merge(marked.defaults, opt);
18748 marked.defaults = {
18759 langPrefix: 'lang-',
18760 smartypants: false,
18762 renderer: new Renderer,
18770 marked.Parser = Parser;
18771 marked.parser = Parser.parse;
18773 marked.Renderer = Renderer;
18775 marked.Lexer = Lexer;
18776 marked.lexer = Lexer.lex;
18778 marked.InlineLexer = InlineLexer;
18779 marked.inlineLexer = InlineLexer.output;
18781 marked.parse = marked;
18783 Roo.Markdown.marked = marked;
18787 * Ext JS Library 1.1.1
18788 * Copyright(c) 2006-2007, Ext JS, LLC.
18790 * Originally Released Under LGPL - original licence link has changed is not relivant.
18793 * <script type="text/javascript">
18799 * These classes are derivatives of the similarly named classes in the YUI Library.
18800 * The original license:
18801 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
18802 * Code licensed under the BSD License:
18803 * http://developer.yahoo.net/yui/license.txt
18808 var Event=Roo.EventManager;
18809 var Dom=Roo.lib.Dom;
18812 * @class Roo.dd.DragDrop
18813 * @extends Roo.util.Observable
18814 * Defines the interface and base operation of items that that can be
18815 * dragged or can be drop targets. It was designed to be extended, overriding
18816 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
18817 * Up to three html elements can be associated with a DragDrop instance:
18819 * <li>linked element: the element that is passed into the constructor.
18820 * This is the element which defines the boundaries for interaction with
18821 * other DragDrop objects.</li>
18822 * <li>handle element(s): The drag operation only occurs if the element that
18823 * was clicked matches a handle element. By default this is the linked
18824 * element, but there are times that you will want only a portion of the
18825 * linked element to initiate the drag operation, and the setHandleElId()
18826 * method provides a way to define this.</li>
18827 * <li>drag element: this represents the element that would be moved along
18828 * with the cursor during a drag operation. By default, this is the linked
18829 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
18830 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
18833 * This class should not be instantiated until the onload event to ensure that
18834 * the associated elements are available.
18835 * The following would define a DragDrop obj that would interact with any
18836 * other DragDrop obj in the "group1" group:
18838 * dd = new Roo.dd.DragDrop("div1", "group1");
18840 * Since none of the event handlers have been implemented, nothing would
18841 * actually happen if you were to run the code above. Normally you would
18842 * override this class or one of the default implementations, but you can
18843 * also override the methods you want on an instance of the class...
18845 * dd.onDragDrop = function(e, id) {
18846 * alert("dd was dropped on " + id);
18850 * @param {String} id of the element that is linked to this instance
18851 * @param {String} sGroup the group of related DragDrop objects
18852 * @param {object} config an object containing configurable attributes
18853 * Valid properties for DragDrop:
18854 * padding, isTarget, maintainOffset, primaryButtonOnly
18856 Roo.dd.DragDrop = function(id, sGroup, config) {
18858 this.init(id, sGroup, config);
18863 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
18866 * The id of the element associated with this object. This is what we
18867 * refer to as the "linked element" because the size and position of
18868 * this element is used to determine when the drag and drop objects have
18876 * Configuration attributes passed into the constructor
18883 * The id of the element that will be dragged. By default this is same
18884 * as the linked element , but could be changed to another element. Ex:
18886 * @property dragElId
18893 * the id of the element that initiates the drag operation. By default
18894 * this is the linked element, but could be changed to be a child of this
18895 * element. This lets us do things like only starting the drag when the
18896 * header element within the linked html element is clicked.
18897 * @property handleElId
18904 * An associative array of HTML tags that will be ignored if clicked.
18905 * @property invalidHandleTypes
18906 * @type {string: string}
18908 invalidHandleTypes: null,
18911 * An associative array of ids for elements that will be ignored if clicked
18912 * @property invalidHandleIds
18913 * @type {string: string}
18915 invalidHandleIds: null,
18918 * An indexted array of css class names for elements that will be ignored
18920 * @property invalidHandleClasses
18923 invalidHandleClasses: null,
18926 * The linked element's absolute X position at the time the drag was
18928 * @property startPageX
18935 * The linked element's absolute X position at the time the drag was
18937 * @property startPageY
18944 * The group defines a logical collection of DragDrop objects that are
18945 * related. Instances only get events when interacting with other
18946 * DragDrop object in the same group. This lets us define multiple
18947 * groups using a single DragDrop subclass if we want.
18949 * @type {string: string}
18954 * Individual drag/drop instances can be locked. This will prevent
18955 * onmousedown start drag.
18963 * Lock this instance
18966 lock: function() { this.locked = true; },
18969 * Unlock this instace
18972 unlock: function() { this.locked = false; },
18975 * By default, all insances can be a drop target. This can be disabled by
18976 * setting isTarget to false.
18983 * The padding configured for this drag and drop object for calculating
18984 * the drop zone intersection with this object.
18991 * Cached reference to the linked element
18992 * @property _domRef
18998 * Internal typeof flag
18999 * @property __ygDragDrop
19002 __ygDragDrop: true,
19005 * Set to true when horizontal contraints are applied
19006 * @property constrainX
19013 * Set to true when vertical contraints are applied
19014 * @property constrainY
19021 * The left constraint
19029 * The right constraint
19037 * The up constraint
19046 * The down constraint
19054 * Maintain offsets when we resetconstraints. Set to true when you want
19055 * the position of the element relative to its parent to stay the same
19056 * when the page changes
19058 * @property maintainOffset
19061 maintainOffset: false,
19064 * Array of pixel locations the element will snap to if we specified a
19065 * horizontal graduation/interval. This array is generated automatically
19066 * when you define a tick interval.
19073 * Array of pixel locations the element will snap to if we specified a
19074 * vertical graduation/interval. This array is generated automatically
19075 * when you define a tick interval.
19082 * By default the drag and drop instance will only respond to the primary
19083 * button click (left button for a right-handed mouse). Set to true to
19084 * allow drag and drop to start with any mouse click that is propogated
19086 * @property primaryButtonOnly
19089 primaryButtonOnly: true,
19092 * The availabe property is false until the linked dom element is accessible.
19093 * @property available
19099 * By default, drags can only be initiated if the mousedown occurs in the
19100 * region the linked element is. This is done in part to work around a
19101 * bug in some browsers that mis-report the mousedown if the previous
19102 * mouseup happened outside of the window. This property is set to true
19103 * if outer handles are defined.
19105 * @property hasOuterHandles
19109 hasOuterHandles: false,
19112 * Code that executes immediately before the startDrag event
19113 * @method b4StartDrag
19116 b4StartDrag: function(x, y) { },
19119 * Abstract method called after a drag/drop object is clicked
19120 * and the drag or mousedown time thresholds have beeen met.
19121 * @method startDrag
19122 * @param {int} X click location
19123 * @param {int} Y click location
19125 startDrag: function(x, y) { /* override this */ },
19128 * Code that executes immediately before the onDrag event
19132 b4Drag: function(e) { },
19135 * Abstract method called during the onMouseMove event while dragging an
19138 * @param {Event} e the mousemove event
19140 onDrag: function(e) { /* override this */ },
19143 * Abstract method called when this element fist begins hovering over
19144 * another DragDrop obj
19145 * @method onDragEnter
19146 * @param {Event} e the mousemove event
19147 * @param {String|DragDrop[]} id In POINT mode, the element
19148 * id this is hovering over. In INTERSECT mode, an array of one or more
19149 * dragdrop items being hovered over.
19151 onDragEnter: function(e, id) { /* override this */ },
19154 * Code that executes immediately before the onDragOver event
19155 * @method b4DragOver
19158 b4DragOver: function(e) { },
19161 * Abstract method called when this element is hovering over another
19163 * @method onDragOver
19164 * @param {Event} e the mousemove event
19165 * @param {String|DragDrop[]} id In POINT mode, the element
19166 * id this is hovering over. In INTERSECT mode, an array of dd items
19167 * being hovered over.
19169 onDragOver: function(e, id) { /* override this */ },
19172 * Code that executes immediately before the onDragOut event
19173 * @method b4DragOut
19176 b4DragOut: function(e) { },
19179 * Abstract method called when we are no longer hovering over an element
19180 * @method onDragOut
19181 * @param {Event} e the mousemove event
19182 * @param {String|DragDrop[]} id In POINT mode, the element
19183 * id this was hovering over. In INTERSECT mode, an array of dd items
19184 * that the mouse is no longer over.
19186 onDragOut: function(e, id) { /* override this */ },
19189 * Code that executes immediately before the onDragDrop event
19190 * @method b4DragDrop
19193 b4DragDrop: function(e) { },
19196 * Abstract method called when this item is dropped on another DragDrop
19198 * @method onDragDrop
19199 * @param {Event} e the mouseup event
19200 * @param {String|DragDrop[]} id In POINT mode, the element
19201 * id this was dropped on. In INTERSECT mode, an array of dd items this
19204 onDragDrop: function(e, id) { /* override this */ },
19207 * Abstract method called when this item is dropped on an area with no
19209 * @method onInvalidDrop
19210 * @param {Event} e the mouseup event
19212 onInvalidDrop: function(e) { /* override this */ },
19215 * Code that executes immediately before the endDrag event
19216 * @method b4EndDrag
19219 b4EndDrag: function(e) { },
19222 * Fired when we are done dragging the object
19224 * @param {Event} e the mouseup event
19226 endDrag: function(e) { /* override this */ },
19229 * Code executed immediately before the onMouseDown event
19230 * @method b4MouseDown
19231 * @param {Event} e the mousedown event
19234 b4MouseDown: function(e) { },
19237 * Event handler that fires when a drag/drop obj gets a mousedown
19238 * @method onMouseDown
19239 * @param {Event} e the mousedown event
19241 onMouseDown: function(e) { /* override this */ },
19244 * Event handler that fires when a drag/drop obj gets a mouseup
19245 * @method onMouseUp
19246 * @param {Event} e the mouseup event
19248 onMouseUp: function(e) { /* override this */ },
19251 * Override the onAvailable method to do what is needed after the initial
19252 * position was determined.
19253 * @method onAvailable
19255 onAvailable: function () {
19259 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
19262 defaultPadding : {left:0, right:0, top:0, bottom:0},
19265 * Initializes the drag drop object's constraints to restrict movement to a certain element.
19269 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
19270 { dragElId: "existingProxyDiv" });
19271 dd.startDrag = function(){
19272 this.constrainTo("parent-id");
19275 * Or you can initalize it using the {@link Roo.Element} object:
19277 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
19278 startDrag : function(){
19279 this.constrainTo("parent-id");
19283 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
19284 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
19285 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
19286 * an object containing the sides to pad. For example: {right:10, bottom:10}
19287 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
19289 constrainTo : function(constrainTo, pad, inContent){
19290 if(typeof pad == "number"){
19291 pad = {left: pad, right:pad, top:pad, bottom:pad};
19293 pad = pad || this.defaultPadding;
19294 var b = Roo.get(this.getEl()).getBox();
19295 var ce = Roo.get(constrainTo);
19296 var s = ce.getScroll();
19297 var c, cd = ce.dom;
19298 if(cd == document.body){
19299 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
19302 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
19306 var topSpace = b.y - c.y;
19307 var leftSpace = b.x - c.x;
19309 this.resetConstraints();
19310 this.setXConstraint(leftSpace - (pad.left||0), // left
19311 c.width - leftSpace - b.width - (pad.right||0) //right
19313 this.setYConstraint(topSpace - (pad.top||0), //top
19314 c.height - topSpace - b.height - (pad.bottom||0) //bottom
19319 * Returns a reference to the linked element
19321 * @return {HTMLElement} the html element
19323 getEl: function() {
19324 if (!this._domRef) {
19325 this._domRef = Roo.getDom(this.id);
19328 return this._domRef;
19332 * Returns a reference to the actual element to drag. By default this is
19333 * the same as the html element, but it can be assigned to another
19334 * element. An example of this can be found in Roo.dd.DDProxy
19335 * @method getDragEl
19336 * @return {HTMLElement} the html element
19338 getDragEl: function() {
19339 return Roo.getDom(this.dragElId);
19343 * Sets up the DragDrop object. Must be called in the constructor of any
19344 * Roo.dd.DragDrop subclass
19346 * @param id the id of the linked element
19347 * @param {String} sGroup the group of related items
19348 * @param {object} config configuration attributes
19350 init: function(id, sGroup, config) {
19351 this.initTarget(id, sGroup, config);
19352 if (!Roo.isTouch) {
19353 Event.on(this.id, "mousedown", this.handleMouseDown, this);
19355 Event.on(this.id, "touchstart", this.handleMouseDown, this);
19356 // Event.on(this.id, "selectstart", Event.preventDefault);
19360 * Initializes Targeting functionality only... the object does not
19361 * get a mousedown handler.
19362 * @method initTarget
19363 * @param id the id of the linked element
19364 * @param {String} sGroup the group of related items
19365 * @param {object} config configuration attributes
19367 initTarget: function(id, sGroup, config) {
19369 // configuration attributes
19370 this.config = config || {};
19372 // create a local reference to the drag and drop manager
19373 this.DDM = Roo.dd.DDM;
19374 // initialize the groups array
19377 // assume that we have an element reference instead of an id if the
19378 // parameter is not a string
19379 if (typeof id !== "string") {
19386 // add to an interaction group
19387 this.addToGroup((sGroup) ? sGroup : "default");
19389 // We don't want to register this as the handle with the manager
19390 // so we just set the id rather than calling the setter.
19391 this.handleElId = id;
19393 // the linked element is the element that gets dragged by default
19394 this.setDragElId(id);
19396 // by default, clicked anchors will not start drag operations.
19397 this.invalidHandleTypes = { A: "A" };
19398 this.invalidHandleIds = {};
19399 this.invalidHandleClasses = [];
19401 this.applyConfig();
19403 this.handleOnAvailable();
19407 * Applies the configuration parameters that were passed into the constructor.
19408 * This is supposed to happen at each level through the inheritance chain. So
19409 * a DDProxy implentation will execute apply config on DDProxy, DD, and
19410 * DragDrop in order to get all of the parameters that are available in
19412 * @method applyConfig
19414 applyConfig: function() {
19416 // configurable properties:
19417 // padding, isTarget, maintainOffset, primaryButtonOnly
19418 this.padding = this.config.padding || [0, 0, 0, 0];
19419 this.isTarget = (this.config.isTarget !== false);
19420 this.maintainOffset = (this.config.maintainOffset);
19421 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
19426 * Executed when the linked element is available
19427 * @method handleOnAvailable
19430 handleOnAvailable: function() {
19431 this.available = true;
19432 this.resetConstraints();
19433 this.onAvailable();
19437 * Configures the padding for the target zone in px. Effectively expands
19438 * (or reduces) the virtual object size for targeting calculations.
19439 * Supports css-style shorthand; if only one parameter is passed, all sides
19440 * will have that padding, and if only two are passed, the top and bottom
19441 * will have the first param, the left and right the second.
19442 * @method setPadding
19443 * @param {int} iTop Top pad
19444 * @param {int} iRight Right pad
19445 * @param {int} iBot Bot pad
19446 * @param {int} iLeft Left pad
19448 setPadding: function(iTop, iRight, iBot, iLeft) {
19449 // this.padding = [iLeft, iRight, iTop, iBot];
19450 if (!iRight && 0 !== iRight) {
19451 this.padding = [iTop, iTop, iTop, iTop];
19452 } else if (!iBot && 0 !== iBot) {
19453 this.padding = [iTop, iRight, iTop, iRight];
19455 this.padding = [iTop, iRight, iBot, iLeft];
19460 * Stores the initial placement of the linked element.
19461 * @method setInitialPosition
19462 * @param {int} diffX the X offset, default 0
19463 * @param {int} diffY the Y offset, default 0
19465 setInitPosition: function(diffX, diffY) {
19466 var el = this.getEl();
19468 if (!this.DDM.verifyEl(el)) {
19472 var dx = diffX || 0;
19473 var dy = diffY || 0;
19475 var p = Dom.getXY( el );
19477 this.initPageX = p[0] - dx;
19478 this.initPageY = p[1] - dy;
19480 this.lastPageX = p[0];
19481 this.lastPageY = p[1];
19484 this.setStartPosition(p);
19488 * Sets the start position of the element. This is set when the obj
19489 * is initialized, the reset when a drag is started.
19490 * @method setStartPosition
19491 * @param pos current position (from previous lookup)
19494 setStartPosition: function(pos) {
19495 var p = pos || Dom.getXY( this.getEl() );
19496 this.deltaSetXY = null;
19498 this.startPageX = p[0];
19499 this.startPageY = p[1];
19503 * Add this instance to a group of related drag/drop objects. All
19504 * instances belong to at least one group, and can belong to as many
19505 * groups as needed.
19506 * @method addToGroup
19507 * @param sGroup {string} the name of the group
19509 addToGroup: function(sGroup) {
19510 this.groups[sGroup] = true;
19511 this.DDM.regDragDrop(this, sGroup);
19515 * Remove's this instance from the supplied interaction group
19516 * @method removeFromGroup
19517 * @param {string} sGroup The group to drop
19519 removeFromGroup: function(sGroup) {
19520 if (this.groups[sGroup]) {
19521 delete this.groups[sGroup];
19524 this.DDM.removeDDFromGroup(this, sGroup);
19528 * Allows you to specify that an element other than the linked element
19529 * will be moved with the cursor during a drag
19530 * @method setDragElId
19531 * @param id {string} the id of the element that will be used to initiate the drag
19533 setDragElId: function(id) {
19534 this.dragElId = id;
19538 * Allows you to specify a child of the linked element that should be
19539 * used to initiate the drag operation. An example of this would be if
19540 * you have a content div with text and links. Clicking anywhere in the
19541 * content area would normally start the drag operation. Use this method
19542 * to specify that an element inside of the content div is the element
19543 * that starts the drag operation.
19544 * @method setHandleElId
19545 * @param id {string} the id of the element that will be used to
19546 * initiate the drag.
19548 setHandleElId: function(id) {
19549 if (typeof id !== "string") {
19552 this.handleElId = id;
19553 this.DDM.regHandle(this.id, id);
19557 * Allows you to set an element outside of the linked element as a drag
19559 * @method setOuterHandleElId
19560 * @param id the id of the element that will be used to initiate the drag
19562 setOuterHandleElId: function(id) {
19563 if (typeof id !== "string") {
19566 Event.on(id, "mousedown",
19567 this.handleMouseDown, this);
19568 this.setHandleElId(id);
19570 this.hasOuterHandles = true;
19574 * Remove all drag and drop hooks for this element
19577 unreg: function() {
19578 Event.un(this.id, "mousedown",
19579 this.handleMouseDown);
19580 Event.un(this.id, "touchstart",
19581 this.handleMouseDown);
19582 this._domRef = null;
19583 this.DDM._remove(this);
19586 destroy : function(){
19591 * Returns true if this instance is locked, or the drag drop mgr is locked
19592 * (meaning that all drag/drop is disabled on the page.)
19594 * @return {boolean} true if this obj or all drag/drop is locked, else
19597 isLocked: function() {
19598 return (this.DDM.isLocked() || this.locked);
19602 * Fired when this object is clicked
19603 * @method handleMouseDown
19605 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
19608 handleMouseDown: function(e, oDD){
19610 if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
19611 //Roo.log('not touch/ button !=0');
19614 if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
19615 return; // double touch..
19619 if (this.isLocked()) {
19620 //Roo.log('locked');
19624 this.DDM.refreshCache(this.groups);
19625 // Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
19626 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
19627 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
19628 //Roo.log('no outer handes or not over target');
19631 // Roo.log('check validator');
19632 if (this.clickValidator(e)) {
19633 // Roo.log('validate success');
19634 // set the initial element position
19635 this.setStartPosition();
19638 this.b4MouseDown(e);
19639 this.onMouseDown(e);
19641 this.DDM.handleMouseDown(e, this);
19643 this.DDM.stopEvent(e);
19651 clickValidator: function(e) {
19652 var target = e.getTarget();
19653 return ( this.isValidHandleChild(target) &&
19654 (this.id == this.handleElId ||
19655 this.DDM.handleWasClicked(target, this.id)) );
19659 * Allows you to specify a tag name that should not start a drag operation
19660 * when clicked. This is designed to facilitate embedding links within a
19661 * drag handle that do something other than start the drag.
19662 * @method addInvalidHandleType
19663 * @param {string} tagName the type of element to exclude
19665 addInvalidHandleType: function(tagName) {
19666 var type = tagName.toUpperCase();
19667 this.invalidHandleTypes[type] = type;
19671 * Lets you to specify an element id for a child of a drag handle
19672 * that should not initiate a drag
19673 * @method addInvalidHandleId
19674 * @param {string} id the element id of the element you wish to ignore
19676 addInvalidHandleId: function(id) {
19677 if (typeof id !== "string") {
19680 this.invalidHandleIds[id] = id;
19684 * Lets you specify a css class of elements that will not initiate a drag
19685 * @method addInvalidHandleClass
19686 * @param {string} cssClass the class of the elements you wish to ignore
19688 addInvalidHandleClass: function(cssClass) {
19689 this.invalidHandleClasses.push(cssClass);
19693 * Unsets an excluded tag name set by addInvalidHandleType
19694 * @method removeInvalidHandleType
19695 * @param {string} tagName the type of element to unexclude
19697 removeInvalidHandleType: function(tagName) {
19698 var type = tagName.toUpperCase();
19699 // this.invalidHandleTypes[type] = null;
19700 delete this.invalidHandleTypes[type];
19704 * Unsets an invalid handle id
19705 * @method removeInvalidHandleId
19706 * @param {string} id the id of the element to re-enable
19708 removeInvalidHandleId: function(id) {
19709 if (typeof id !== "string") {
19712 delete this.invalidHandleIds[id];
19716 * Unsets an invalid css class
19717 * @method removeInvalidHandleClass
19718 * @param {string} cssClass the class of the element(s) you wish to
19721 removeInvalidHandleClass: function(cssClass) {
19722 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
19723 if (this.invalidHandleClasses[i] == cssClass) {
19724 delete this.invalidHandleClasses[i];
19730 * Checks the tag exclusion list to see if this click should be ignored
19731 * @method isValidHandleChild
19732 * @param {HTMLElement} node the HTMLElement to evaluate
19733 * @return {boolean} true if this is a valid tag type, false if not
19735 isValidHandleChild: function(node) {
19738 // var n = (node.nodeName == "#text") ? node.parentNode : node;
19741 nodeName = node.nodeName.toUpperCase();
19743 nodeName = node.nodeName;
19745 valid = valid && !this.invalidHandleTypes[nodeName];
19746 valid = valid && !this.invalidHandleIds[node.id];
19748 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
19749 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
19758 * Create the array of horizontal tick marks if an interval was specified
19759 * in setXConstraint().
19760 * @method setXTicks
19763 setXTicks: function(iStartX, iTickSize) {
19765 this.xTickSize = iTickSize;
19769 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
19771 this.xTicks[this.xTicks.length] = i;
19776 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
19778 this.xTicks[this.xTicks.length] = i;
19783 this.xTicks.sort(this.DDM.numericSort) ;
19787 * Create the array of vertical tick marks if an interval was specified in
19788 * setYConstraint().
19789 * @method setYTicks
19792 setYTicks: function(iStartY, iTickSize) {
19794 this.yTickSize = iTickSize;
19798 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
19800 this.yTicks[this.yTicks.length] = i;
19805 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
19807 this.yTicks[this.yTicks.length] = i;
19812 this.yTicks.sort(this.DDM.numericSort) ;
19816 * By default, the element can be dragged any place on the screen. Use
19817 * this method to limit the horizontal travel of the element. Pass in
19818 * 0,0 for the parameters if you want to lock the drag to the y axis.
19819 * @method setXConstraint
19820 * @param {int} iLeft the number of pixels the element can move to the left
19821 * @param {int} iRight the number of pixels the element can move to the
19823 * @param {int} iTickSize optional parameter for specifying that the
19825 * should move iTickSize pixels at a time.
19827 setXConstraint: function(iLeft, iRight, iTickSize) {
19828 this.leftConstraint = iLeft;
19829 this.rightConstraint = iRight;
19831 this.minX = this.initPageX - iLeft;
19832 this.maxX = this.initPageX + iRight;
19833 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
19835 this.constrainX = true;
19839 * Clears any constraints applied to this instance. Also clears ticks
19840 * since they can't exist independent of a constraint at this time.
19841 * @method clearConstraints
19843 clearConstraints: function() {
19844 this.constrainX = false;
19845 this.constrainY = false;
19850 * Clears any tick interval defined for this instance
19851 * @method clearTicks
19853 clearTicks: function() {
19854 this.xTicks = null;
19855 this.yTicks = null;
19856 this.xTickSize = 0;
19857 this.yTickSize = 0;
19861 * By default, the element can be dragged any place on the screen. Set
19862 * this to limit the vertical travel of the element. Pass in 0,0 for the
19863 * parameters if you want to lock the drag to the x axis.
19864 * @method setYConstraint
19865 * @param {int} iUp the number of pixels the element can move up
19866 * @param {int} iDown the number of pixels the element can move down
19867 * @param {int} iTickSize optional parameter for specifying that the
19868 * element should move iTickSize pixels at a time.
19870 setYConstraint: function(iUp, iDown, iTickSize) {
19871 this.topConstraint = iUp;
19872 this.bottomConstraint = iDown;
19874 this.minY = this.initPageY - iUp;
19875 this.maxY = this.initPageY + iDown;
19876 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
19878 this.constrainY = true;
19883 * resetConstraints must be called if you manually reposition a dd element.
19884 * @method resetConstraints
19885 * @param {boolean} maintainOffset
19887 resetConstraints: function() {
19890 // Maintain offsets if necessary
19891 if (this.initPageX || this.initPageX === 0) {
19892 // figure out how much this thing has moved
19893 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
19894 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
19896 this.setInitPosition(dx, dy);
19898 // This is the first time we have detected the element's position
19900 this.setInitPosition();
19903 if (this.constrainX) {
19904 this.setXConstraint( this.leftConstraint,
19905 this.rightConstraint,
19909 if (this.constrainY) {
19910 this.setYConstraint( this.topConstraint,
19911 this.bottomConstraint,
19917 * Normally the drag element is moved pixel by pixel, but we can specify
19918 * that it move a number of pixels at a time. This method resolves the
19919 * location when we have it set up like this.
19921 * @param {int} val where we want to place the object
19922 * @param {int[]} tickArray sorted array of valid points
19923 * @return {int} the closest tick
19926 getTick: function(val, tickArray) {
19929 // If tick interval is not defined, it is effectively 1 pixel,
19930 // so we return the value passed to us.
19932 } else if (tickArray[0] >= val) {
19933 // The value is lower than the first tick, so we return the first
19935 return tickArray[0];
19937 for (var i=0, len=tickArray.length; i<len; ++i) {
19939 if (tickArray[next] && tickArray[next] >= val) {
19940 var diff1 = val - tickArray[i];
19941 var diff2 = tickArray[next] - val;
19942 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
19946 // The value is larger than the last tick, so we return the last
19948 return tickArray[tickArray.length - 1];
19955 * @return {string} string representation of the dd obj
19957 toString: function() {
19958 return ("DragDrop " + this.id);
19966 * Ext JS Library 1.1.1
19967 * Copyright(c) 2006-2007, Ext JS, LLC.
19969 * Originally Released Under LGPL - original licence link has changed is not relivant.
19972 * <script type="text/javascript">
19977 * The drag and drop utility provides a framework for building drag and drop
19978 * applications. In addition to enabling drag and drop for specific elements,
19979 * the drag and drop elements are tracked by the manager class, and the
19980 * interactions between the various elements are tracked during the drag and
19981 * the implementing code is notified about these important moments.
19984 // Only load the library once. Rewriting the manager class would orphan
19985 // existing drag and drop instances.
19986 if (!Roo.dd.DragDropMgr) {
19989 * @class Roo.dd.DragDropMgr
19990 * DragDropMgr is a singleton that tracks the element interaction for
19991 * all DragDrop items in the window. Generally, you will not call
19992 * this class directly, but it does have helper methods that could
19993 * be useful in your DragDrop implementations.
19996 Roo.dd.DragDropMgr = function() {
19998 var Event = Roo.EventManager;
20003 * Two dimensional Array of registered DragDrop objects. The first
20004 * dimension is the DragDrop item group, the second the DragDrop
20007 * @type {string: string}
20014 * Array of element ids defined as drag handles. Used to determine
20015 * if the element that generated the mousedown event is actually the
20016 * handle and not the html element itself.
20017 * @property handleIds
20018 * @type {string: string}
20025 * the DragDrop object that is currently being dragged
20026 * @property dragCurrent
20034 * the DragDrop object(s) that are being hovered over
20035 * @property dragOvers
20043 * the X distance between the cursor and the object being dragged
20052 * the Y distance between the cursor and the object being dragged
20061 * Flag to determine if we should prevent the default behavior of the
20062 * events we define. By default this is true, but this can be set to
20063 * false if you need the default behavior (not recommended)
20064 * @property preventDefault
20068 preventDefault: true,
20071 * Flag to determine if we should stop the propagation of the events
20072 * we generate. This is true by default but you may want to set it to
20073 * false if the html element contains other features that require the
20075 * @property stopPropagation
20079 stopPropagation: true,
20082 * Internal flag that is set to true when drag and drop has been
20084 * @property initialized
20091 * All drag and drop can be disabled.
20099 * Called the first time an element is registered.
20105 this.initialized = true;
20109 * In point mode, drag and drop interaction is defined by the
20110 * location of the cursor during the drag/drop
20118 * In intersect mode, drag and drop interactio nis defined by the
20119 * overlap of two or more drag and drop objects.
20120 * @property INTERSECT
20127 * The current drag and drop mode. Default: POINT
20135 * Runs method on all drag and drop objects
20136 * @method _execOnAll
20140 _execOnAll: function(sMethod, args) {
20141 for (var i in this.ids) {
20142 for (var j in this.ids[i]) {
20143 var oDD = this.ids[i][j];
20144 if (! this.isTypeOfDD(oDD)) {
20147 oDD[sMethod].apply(oDD, args);
20153 * Drag and drop initialization. Sets up the global event handlers
20158 _onLoad: function() {
20162 if (!Roo.isTouch) {
20163 Event.on(document, "mouseup", this.handleMouseUp, this, true);
20164 Event.on(document, "mousemove", this.handleMouseMove, this, true);
20166 Event.on(document, "touchend", this.handleMouseUp, this, true);
20167 Event.on(document, "touchmove", this.handleMouseMove, this, true);
20169 Event.on(window, "unload", this._onUnload, this, true);
20170 Event.on(window, "resize", this._onResize, this, true);
20171 // Event.on(window, "mouseout", this._test);
20176 * Reset constraints on all drag and drop objs
20177 * @method _onResize
20181 _onResize: function(e) {
20182 this._execOnAll("resetConstraints", []);
20186 * Lock all drag and drop functionality
20190 lock: function() { this.locked = true; },
20193 * Unlock all drag and drop functionality
20197 unlock: function() { this.locked = false; },
20200 * Is drag and drop locked?
20202 * @return {boolean} True if drag and drop is locked, false otherwise.
20205 isLocked: function() { return this.locked; },
20208 * Location cache that is set for all drag drop objects when a drag is
20209 * initiated, cleared when the drag is finished.
20210 * @property locationCache
20217 * Set useCache to false if you want to force object the lookup of each
20218 * drag and drop linked element constantly during a drag.
20219 * @property useCache
20226 * The number of pixels that the mouse needs to move after the
20227 * mousedown before the drag is initiated. Default=3;
20228 * @property clickPixelThresh
20232 clickPixelThresh: 3,
20235 * The number of milliseconds after the mousedown event to initiate the
20236 * drag if we don't get a mouseup event. Default=1000
20237 * @property clickTimeThresh
20241 clickTimeThresh: 350,
20244 * Flag that indicates that either the drag pixel threshold or the
20245 * mousdown time threshold has been met
20246 * @property dragThreshMet
20251 dragThreshMet: false,
20254 * Timeout used for the click time threshold
20255 * @property clickTimeout
20260 clickTimeout: null,
20263 * The X position of the mousedown event stored for later use when a
20264 * drag threshold is met.
20273 * The Y position of the mousedown event stored for later use when a
20274 * drag threshold is met.
20283 * Each DragDrop instance must be registered with the DragDropMgr.
20284 * This is executed in DragDrop.init()
20285 * @method regDragDrop
20286 * @param {DragDrop} oDD the DragDrop object to register
20287 * @param {String} sGroup the name of the group this element belongs to
20290 regDragDrop: function(oDD, sGroup) {
20291 if (!this.initialized) { this.init(); }
20293 if (!this.ids[sGroup]) {
20294 this.ids[sGroup] = {};
20296 this.ids[sGroup][oDD.id] = oDD;
20300 * Removes the supplied dd instance from the supplied group. Executed
20301 * by DragDrop.removeFromGroup, so don't call this function directly.
20302 * @method removeDDFromGroup
20306 removeDDFromGroup: function(oDD, sGroup) {
20307 if (!this.ids[sGroup]) {
20308 this.ids[sGroup] = {};
20311 var obj = this.ids[sGroup];
20312 if (obj && obj[oDD.id]) {
20313 delete obj[oDD.id];
20318 * Unregisters a drag and drop item. This is executed in
20319 * DragDrop.unreg, use that method instead of calling this directly.
20324 _remove: function(oDD) {
20325 for (var g in oDD.groups) {
20326 if (g && this.ids[g][oDD.id]) {
20327 delete this.ids[g][oDD.id];
20330 delete this.handleIds[oDD.id];
20334 * Each DragDrop handle element must be registered. This is done
20335 * automatically when executing DragDrop.setHandleElId()
20336 * @method regHandle
20337 * @param {String} sDDId the DragDrop id this element is a handle for
20338 * @param {String} sHandleId the id of the element that is the drag
20342 regHandle: function(sDDId, sHandleId) {
20343 if (!this.handleIds[sDDId]) {
20344 this.handleIds[sDDId] = {};
20346 this.handleIds[sDDId][sHandleId] = sHandleId;
20350 * Utility function to determine if a given element has been
20351 * registered as a drag drop item.
20352 * @method isDragDrop
20353 * @param {String} id the element id to check
20354 * @return {boolean} true if this element is a DragDrop item,
20358 isDragDrop: function(id) {
20359 return ( this.getDDById(id) ) ? true : false;
20363 * Returns the drag and drop instances that are in all groups the
20364 * passed in instance belongs to.
20365 * @method getRelated
20366 * @param {DragDrop} p_oDD the obj to get related data for
20367 * @param {boolean} bTargetsOnly if true, only return targetable objs
20368 * @return {DragDrop[]} the related instances
20371 getRelated: function(p_oDD, bTargetsOnly) {
20373 for (var i in p_oDD.groups) {
20374 for (j in this.ids[i]) {
20375 var dd = this.ids[i][j];
20376 if (! this.isTypeOfDD(dd)) {
20379 if (!bTargetsOnly || dd.isTarget) {
20380 oDDs[oDDs.length] = dd;
20389 * Returns true if the specified dd target is a legal target for
20390 * the specifice drag obj
20391 * @method isLegalTarget
20392 * @param {DragDrop} the drag obj
20393 * @param {DragDrop} the target
20394 * @return {boolean} true if the target is a legal target for the
20398 isLegalTarget: function (oDD, oTargetDD) {
20399 var targets = this.getRelated(oDD, true);
20400 for (var i=0, len=targets.length;i<len;++i) {
20401 if (targets[i].id == oTargetDD.id) {
20410 * My goal is to be able to transparently determine if an object is
20411 * typeof DragDrop, and the exact subclass of DragDrop. typeof
20412 * returns "object", oDD.constructor.toString() always returns
20413 * "DragDrop" and not the name of the subclass. So for now it just
20414 * evaluates a well-known variable in DragDrop.
20415 * @method isTypeOfDD
20416 * @param {Object} the object to evaluate
20417 * @return {boolean} true if typeof oDD = DragDrop
20420 isTypeOfDD: function (oDD) {
20421 return (oDD && oDD.__ygDragDrop);
20425 * Utility function to determine if a given element has been
20426 * registered as a drag drop handle for the given Drag Drop object.
20428 * @param {String} id the element id to check
20429 * @return {boolean} true if this element is a DragDrop handle, false
20433 isHandle: function(sDDId, sHandleId) {
20434 return ( this.handleIds[sDDId] &&
20435 this.handleIds[sDDId][sHandleId] );
20439 * Returns the DragDrop instance for a given id
20440 * @method getDDById
20441 * @param {String} id the id of the DragDrop object
20442 * @return {DragDrop} the drag drop object, null if it is not found
20445 getDDById: function(id) {
20446 for (var i in this.ids) {
20447 if (this.ids[i][id]) {
20448 return this.ids[i][id];
20455 * Fired after a registered DragDrop object gets the mousedown event.
20456 * Sets up the events required to track the object being dragged
20457 * @method handleMouseDown
20458 * @param {Event} e the event
20459 * @param oDD the DragDrop object being dragged
20463 handleMouseDown: function(e, oDD) {
20465 Roo.QuickTips.disable();
20467 this.currentTarget = e.getTarget();
20469 this.dragCurrent = oDD;
20471 var el = oDD.getEl();
20473 // track start position
20474 this.startX = e.getPageX();
20475 this.startY = e.getPageY();
20477 this.deltaX = this.startX - el.offsetLeft;
20478 this.deltaY = this.startY - el.offsetTop;
20480 this.dragThreshMet = false;
20482 this.clickTimeout = setTimeout(
20484 var DDM = Roo.dd.DDM;
20485 DDM.startDrag(DDM.startX, DDM.startY);
20487 this.clickTimeThresh );
20491 * Fired when either the drag pixel threshol or the mousedown hold
20492 * time threshold has been met.
20493 * @method startDrag
20494 * @param x {int} the X position of the original mousedown
20495 * @param y {int} the Y position of the original mousedown
20498 startDrag: function(x, y) {
20499 clearTimeout(this.clickTimeout);
20500 if (this.dragCurrent) {
20501 this.dragCurrent.b4StartDrag(x, y);
20502 this.dragCurrent.startDrag(x, y);
20504 this.dragThreshMet = true;
20508 * Internal function to handle the mouseup event. Will be invoked
20509 * from the context of the document.
20510 * @method handleMouseUp
20511 * @param {Event} e the event
20515 handleMouseUp: function(e) {
20518 Roo.QuickTips.enable();
20520 if (! this.dragCurrent) {
20524 clearTimeout(this.clickTimeout);
20526 if (this.dragThreshMet) {
20527 this.fireEvents(e, true);
20537 * Utility to stop event propagation and event default, if these
20538 * features are turned on.
20539 * @method stopEvent
20540 * @param {Event} e the event as returned by this.getEvent()
20543 stopEvent: function(e){
20544 if(this.stopPropagation) {
20545 e.stopPropagation();
20548 if (this.preventDefault) {
20549 e.preventDefault();
20554 * Internal function to clean up event handlers after the drag
20555 * operation is complete
20557 * @param {Event} e the event
20561 stopDrag: function(e) {
20562 // Fire the drag end event for the item that was dragged
20563 if (this.dragCurrent) {
20564 if (this.dragThreshMet) {
20565 this.dragCurrent.b4EndDrag(e);
20566 this.dragCurrent.endDrag(e);
20569 this.dragCurrent.onMouseUp(e);
20572 this.dragCurrent = null;
20573 this.dragOvers = {};
20577 * Internal function to handle the mousemove event. Will be invoked
20578 * from the context of the html element.
20580 * @TODO figure out what we can do about mouse events lost when the
20581 * user drags objects beyond the window boundary. Currently we can
20582 * detect this in internet explorer by verifying that the mouse is
20583 * down during the mousemove event. Firefox doesn't give us the
20584 * button state on the mousemove event.
20585 * @method handleMouseMove
20586 * @param {Event} e the event
20590 handleMouseMove: function(e) {
20591 if (! this.dragCurrent) {
20595 // var button = e.which || e.button;
20597 // check for IE mouseup outside of page boundary
20598 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
20600 return this.handleMouseUp(e);
20603 if (!this.dragThreshMet) {
20604 var diffX = Math.abs(this.startX - e.getPageX());
20605 var diffY = Math.abs(this.startY - e.getPageY());
20606 if (diffX > this.clickPixelThresh ||
20607 diffY > this.clickPixelThresh) {
20608 this.startDrag(this.startX, this.startY);
20612 if (this.dragThreshMet) {
20613 this.dragCurrent.b4Drag(e);
20614 this.dragCurrent.onDrag(e);
20615 if(!this.dragCurrent.moveOnly){
20616 this.fireEvents(e, false);
20626 * Iterates over all of the DragDrop elements to find ones we are
20627 * hovering over or dropping on
20628 * @method fireEvents
20629 * @param {Event} e the event
20630 * @param {boolean} isDrop is this a drop op or a mouseover op?
20634 fireEvents: function(e, isDrop) {
20635 var dc = this.dragCurrent;
20637 // If the user did the mouse up outside of the window, we could
20638 // get here even though we have ended the drag.
20639 if (!dc || dc.isLocked()) {
20643 var pt = e.getPoint();
20645 // cache the previous dragOver array
20651 var enterEvts = [];
20653 // Check to see if the object(s) we were hovering over is no longer
20654 // being hovered over so we can fire the onDragOut event
20655 for (var i in this.dragOvers) {
20657 var ddo = this.dragOvers[i];
20659 if (! this.isTypeOfDD(ddo)) {
20663 if (! this.isOverTarget(pt, ddo, this.mode)) {
20664 outEvts.push( ddo );
20667 oldOvers[i] = true;
20668 delete this.dragOvers[i];
20671 for (var sGroup in dc.groups) {
20673 if ("string" != typeof sGroup) {
20677 for (i in this.ids[sGroup]) {
20678 var oDD = this.ids[sGroup][i];
20679 if (! this.isTypeOfDD(oDD)) {
20683 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
20684 if (this.isOverTarget(pt, oDD, this.mode)) {
20685 // look for drop interactions
20687 dropEvts.push( oDD );
20688 // look for drag enter and drag over interactions
20691 // initial drag over: dragEnter fires
20692 if (!oldOvers[oDD.id]) {
20693 enterEvts.push( oDD );
20694 // subsequent drag overs: dragOver fires
20696 overEvts.push( oDD );
20699 this.dragOvers[oDD.id] = oDD;
20707 if (outEvts.length) {
20708 dc.b4DragOut(e, outEvts);
20709 dc.onDragOut(e, outEvts);
20712 if (enterEvts.length) {
20713 dc.onDragEnter(e, enterEvts);
20716 if (overEvts.length) {
20717 dc.b4DragOver(e, overEvts);
20718 dc.onDragOver(e, overEvts);
20721 if (dropEvts.length) {
20722 dc.b4DragDrop(e, dropEvts);
20723 dc.onDragDrop(e, dropEvts);
20727 // fire dragout events
20729 for (i=0, len=outEvts.length; i<len; ++i) {
20730 dc.b4DragOut(e, outEvts[i].id);
20731 dc.onDragOut(e, outEvts[i].id);
20734 // fire enter events
20735 for (i=0,len=enterEvts.length; i<len; ++i) {
20736 // dc.b4DragEnter(e, oDD.id);
20737 dc.onDragEnter(e, enterEvts[i].id);
20740 // fire over events
20741 for (i=0,len=overEvts.length; i<len; ++i) {
20742 dc.b4DragOver(e, overEvts[i].id);
20743 dc.onDragOver(e, overEvts[i].id);
20746 // fire drop events
20747 for (i=0, len=dropEvts.length; i<len; ++i) {
20748 dc.b4DragDrop(e, dropEvts[i].id);
20749 dc.onDragDrop(e, dropEvts[i].id);
20754 // notify about a drop that did not find a target
20755 if (isDrop && !dropEvts.length) {
20756 dc.onInvalidDrop(e);
20762 * Helper function for getting the best match from the list of drag
20763 * and drop objects returned by the drag and drop events when we are
20764 * in INTERSECT mode. It returns either the first object that the
20765 * cursor is over, or the object that has the greatest overlap with
20766 * the dragged element.
20767 * @method getBestMatch
20768 * @param {DragDrop[]} dds The array of drag and drop objects
20770 * @return {DragDrop} The best single match
20773 getBestMatch: function(dds) {
20775 // Return null if the input is not what we expect
20776 //if (!dds || !dds.length || dds.length == 0) {
20778 // If there is only one item, it wins
20779 //} else if (dds.length == 1) {
20781 var len = dds.length;
20786 // Loop through the targeted items
20787 for (var i=0; i<len; ++i) {
20789 // If the cursor is over the object, it wins. If the
20790 // cursor is over multiple matches, the first one we come
20792 if (dd.cursorIsOver) {
20795 // Otherwise the object with the most overlap wins
20798 winner.overlap.getArea() < dd.overlap.getArea()) {
20809 * Refreshes the cache of the top-left and bottom-right points of the
20810 * drag and drop objects in the specified group(s). This is in the
20811 * format that is stored in the drag and drop instance, so typical
20814 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
20818 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
20820 * @TODO this really should be an indexed array. Alternatively this
20821 * method could accept both.
20822 * @method refreshCache
20823 * @param {Object} groups an associative array of groups to refresh
20826 refreshCache: function(groups) {
20827 for (var sGroup in groups) {
20828 if ("string" != typeof sGroup) {
20831 for (var i in this.ids[sGroup]) {
20832 var oDD = this.ids[sGroup][i];
20834 if (this.isTypeOfDD(oDD)) {
20835 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
20836 var loc = this.getLocation(oDD);
20838 this.locationCache[oDD.id] = loc;
20840 delete this.locationCache[oDD.id];
20841 // this will unregister the drag and drop object if
20842 // the element is not in a usable state
20851 * This checks to make sure an element exists and is in the DOM. The
20852 * main purpose is to handle cases where innerHTML is used to remove
20853 * drag and drop objects from the DOM. IE provides an 'unspecified
20854 * error' when trying to access the offsetParent of such an element
20856 * @param {HTMLElement} el the element to check
20857 * @return {boolean} true if the element looks usable
20860 verifyEl: function(el) {
20865 parent = el.offsetParent;
20868 parent = el.offsetParent;
20879 * Returns a Region object containing the drag and drop element's position
20880 * and size, including the padding configured for it
20881 * @method getLocation
20882 * @param {DragDrop} oDD the drag and drop object to get the
20884 * @return {Roo.lib.Region} a Region object representing the total area
20885 * the element occupies, including any padding
20886 * the instance is configured for.
20889 getLocation: function(oDD) {
20890 if (! this.isTypeOfDD(oDD)) {
20894 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
20897 pos= Roo.lib.Dom.getXY(el);
20905 x2 = x1 + el.offsetWidth;
20907 y2 = y1 + el.offsetHeight;
20909 t = y1 - oDD.padding[0];
20910 r = x2 + oDD.padding[1];
20911 b = y2 + oDD.padding[2];
20912 l = x1 - oDD.padding[3];
20914 return new Roo.lib.Region( t, r, b, l );
20918 * Checks the cursor location to see if it over the target
20919 * @method isOverTarget
20920 * @param {Roo.lib.Point} pt The point to evaluate
20921 * @param {DragDrop} oTarget the DragDrop object we are inspecting
20922 * @return {boolean} true if the mouse is over the target
20926 isOverTarget: function(pt, oTarget, intersect) {
20927 // use cache if available
20928 var loc = this.locationCache[oTarget.id];
20929 if (!loc || !this.useCache) {
20930 loc = this.getLocation(oTarget);
20931 this.locationCache[oTarget.id] = loc;
20939 oTarget.cursorIsOver = loc.contains( pt );
20941 // DragDrop is using this as a sanity check for the initial mousedown
20942 // in this case we are done. In POINT mode, if the drag obj has no
20943 // contraints, we are also done. Otherwise we need to evaluate the
20944 // location of the target as related to the actual location of the
20945 // dragged element.
20946 var dc = this.dragCurrent;
20947 if (!dc || !dc.getTargetCoord ||
20948 (!intersect && !dc.constrainX && !dc.constrainY)) {
20949 return oTarget.cursorIsOver;
20952 oTarget.overlap = null;
20954 // Get the current location of the drag element, this is the
20955 // location of the mouse event less the delta that represents
20956 // where the original mousedown happened on the element. We
20957 // need to consider constraints and ticks as well.
20958 var pos = dc.getTargetCoord(pt.x, pt.y);
20960 var el = dc.getDragEl();
20961 var curRegion = new Roo.lib.Region( pos.y,
20962 pos.x + el.offsetWidth,
20963 pos.y + el.offsetHeight,
20966 var overlap = curRegion.intersect(loc);
20969 oTarget.overlap = overlap;
20970 return (intersect) ? true : oTarget.cursorIsOver;
20977 * unload event handler
20978 * @method _onUnload
20982 _onUnload: function(e, me) {
20983 Roo.dd.DragDropMgr.unregAll();
20987 * Cleans up the drag and drop events and objects.
20992 unregAll: function() {
20994 if (this.dragCurrent) {
20996 this.dragCurrent = null;
20999 this._execOnAll("unreg", []);
21001 for (i in this.elementCache) {
21002 delete this.elementCache[i];
21005 this.elementCache = {};
21010 * A cache of DOM elements
21011 * @property elementCache
21018 * Get the wrapper for the DOM element specified
21019 * @method getElWrapper
21020 * @param {String} id the id of the element to get
21021 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
21023 * @deprecated This wrapper isn't that useful
21026 getElWrapper: function(id) {
21027 var oWrapper = this.elementCache[id];
21028 if (!oWrapper || !oWrapper.el) {
21029 oWrapper = this.elementCache[id] =
21030 new this.ElementWrapper(Roo.getDom(id));
21036 * Returns the actual DOM element
21037 * @method getElement
21038 * @param {String} id the id of the elment to get
21039 * @return {Object} The element
21040 * @deprecated use Roo.getDom instead
21043 getElement: function(id) {
21044 return Roo.getDom(id);
21048 * Returns the style property for the DOM element (i.e.,
21049 * document.getElById(id).style)
21051 * @param {String} id the id of the elment to get
21052 * @return {Object} The style property of the element
21053 * @deprecated use Roo.getDom instead
21056 getCss: function(id) {
21057 var el = Roo.getDom(id);
21058 return (el) ? el.style : null;
21062 * Inner class for cached elements
21063 * @class DragDropMgr.ElementWrapper
21068 ElementWrapper: function(el) {
21073 this.el = el || null;
21078 this.id = this.el && el.id;
21080 * A reference to the style property
21083 this.css = this.el && el.style;
21087 * Returns the X position of an html element
21089 * @param el the element for which to get the position
21090 * @return {int} the X coordinate
21092 * @deprecated use Roo.lib.Dom.getX instead
21095 getPosX: function(el) {
21096 return Roo.lib.Dom.getX(el);
21100 * Returns the Y position of an html element
21102 * @param el the element for which to get the position
21103 * @return {int} the Y coordinate
21104 * @deprecated use Roo.lib.Dom.getY instead
21107 getPosY: function(el) {
21108 return Roo.lib.Dom.getY(el);
21112 * Swap two nodes. In IE, we use the native method, for others we
21113 * emulate the IE behavior
21115 * @param n1 the first node to swap
21116 * @param n2 the other node to swap
21119 swapNode: function(n1, n2) {
21123 var p = n2.parentNode;
21124 var s = n2.nextSibling;
21127 p.insertBefore(n1, n2);
21128 } else if (n2 == n1.nextSibling) {
21129 p.insertBefore(n2, n1);
21131 n1.parentNode.replaceChild(n2, n1);
21132 p.insertBefore(n1, s);
21138 * Returns the current scroll position
21139 * @method getScroll
21143 getScroll: function () {
21144 var t, l, dde=document.documentElement, db=document.body;
21145 if (dde && (dde.scrollTop || dde.scrollLeft)) {
21147 l = dde.scrollLeft;
21154 return { top: t, left: l };
21158 * Returns the specified element style property
21160 * @param {HTMLElement} el the element
21161 * @param {string} styleProp the style property
21162 * @return {string} The value of the style property
21163 * @deprecated use Roo.lib.Dom.getStyle
21166 getStyle: function(el, styleProp) {
21167 return Roo.fly(el).getStyle(styleProp);
21171 * Gets the scrollTop
21172 * @method getScrollTop
21173 * @return {int} the document's scrollTop
21176 getScrollTop: function () { return this.getScroll().top; },
21179 * Gets the scrollLeft
21180 * @method getScrollLeft
21181 * @return {int} the document's scrollTop
21184 getScrollLeft: function () { return this.getScroll().left; },
21187 * Sets the x/y position of an element to the location of the
21190 * @param {HTMLElement} moveEl The element to move
21191 * @param {HTMLElement} targetEl The position reference element
21194 moveToEl: function (moveEl, targetEl) {
21195 var aCoord = Roo.lib.Dom.getXY(targetEl);
21196 Roo.lib.Dom.setXY(moveEl, aCoord);
21200 * Numeric array sort function
21201 * @method numericSort
21204 numericSort: function(a, b) { return (a - b); },
21208 * @property _timeoutCount
21215 * Trying to make the load order less important. Without this we get
21216 * an error if this file is loaded before the Event Utility.
21217 * @method _addListeners
21221 _addListeners: function() {
21222 var DDM = Roo.dd.DDM;
21223 if ( Roo.lib.Event && document ) {
21226 if (DDM._timeoutCount > 2000) {
21228 setTimeout(DDM._addListeners, 10);
21229 if (document && document.body) {
21230 DDM._timeoutCount += 1;
21237 * Recursively searches the immediate parent and all child nodes for
21238 * the handle element in order to determine wheter or not it was
21240 * @method handleWasClicked
21241 * @param node the html element to inspect
21244 handleWasClicked: function(node, id) {
21245 if (this.isHandle(id, node.id)) {
21248 // check to see if this is a text node child of the one we want
21249 var p = node.parentNode;
21252 if (this.isHandle(id, p.id)) {
21267 // shorter alias, save a few bytes
21268 Roo.dd.DDM = Roo.dd.DragDropMgr;
21269 Roo.dd.DDM._addListeners();
21273 * Ext JS Library 1.1.1
21274 * Copyright(c) 2006-2007, Ext JS, LLC.
21276 * Originally Released Under LGPL - original licence link has changed is not relivant.
21279 * <script type="text/javascript">
21284 * A DragDrop implementation where the linked element follows the
21285 * mouse cursor during a drag.
21286 * @extends Roo.dd.DragDrop
21288 * @param {String} id the id of the linked element
21289 * @param {String} sGroup the group of related DragDrop items
21290 * @param {object} config an object containing configurable attributes
21291 * Valid properties for DD:
21294 Roo.dd.DD = function(id, sGroup, config) {
21296 this.init(id, sGroup, config);
21300 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
21303 * When set to true, the utility automatically tries to scroll the browser
21304 * window wehn a drag and drop element is dragged near the viewport boundary.
21305 * Defaults to true.
21312 * Sets the pointer offset to the distance between the linked element's top
21313 * left corner and the location the element was clicked
21314 * @method autoOffset
21315 * @param {int} iPageX the X coordinate of the click
21316 * @param {int} iPageY the Y coordinate of the click
21318 autoOffset: function(iPageX, iPageY) {
21319 var x = iPageX - this.startPageX;
21320 var y = iPageY - this.startPageY;
21321 this.setDelta(x, y);
21325 * Sets the pointer offset. You can call this directly to force the
21326 * offset to be in a particular location (e.g., pass in 0,0 to set it
21327 * to the center of the object)
21329 * @param {int} iDeltaX the distance from the left
21330 * @param {int} iDeltaY the distance from the top
21332 setDelta: function(iDeltaX, iDeltaY) {
21333 this.deltaX = iDeltaX;
21334 this.deltaY = iDeltaY;
21338 * Sets the drag element to the location of the mousedown or click event,
21339 * maintaining the cursor location relative to the location on the element
21340 * that was clicked. Override this if you want to place the element in a
21341 * location other than where the cursor is.
21342 * @method setDragElPos
21343 * @param {int} iPageX the X coordinate of the mousedown or drag event
21344 * @param {int} iPageY the Y coordinate of the mousedown or drag event
21346 setDragElPos: function(iPageX, iPageY) {
21347 // the first time we do this, we are going to check to make sure
21348 // the element has css positioning
21350 var el = this.getDragEl();
21351 this.alignElWithMouse(el, iPageX, iPageY);
21355 * Sets the element to the location of the mousedown or click event,
21356 * maintaining the cursor location relative to the location on the element
21357 * that was clicked. Override this if you want to place the element in a
21358 * location other than where the cursor is.
21359 * @method alignElWithMouse
21360 * @param {HTMLElement} el the element to move
21361 * @param {int} iPageX the X coordinate of the mousedown or drag event
21362 * @param {int} iPageY the Y coordinate of the mousedown or drag event
21364 alignElWithMouse: function(el, iPageX, iPageY) {
21365 var oCoord = this.getTargetCoord(iPageX, iPageY);
21366 var fly = el.dom ? el : Roo.fly(el);
21367 if (!this.deltaSetXY) {
21368 var aCoord = [oCoord.x, oCoord.y];
21370 var newLeft = fly.getLeft(true);
21371 var newTop = fly.getTop(true);
21372 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
21374 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
21377 this.cachePosition(oCoord.x, oCoord.y);
21378 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
21383 * Saves the most recent position so that we can reset the constraints and
21384 * tick marks on-demand. We need to know this so that we can calculate the
21385 * number of pixels the element is offset from its original position.
21386 * @method cachePosition
21387 * @param iPageX the current x position (optional, this just makes it so we
21388 * don't have to look it up again)
21389 * @param iPageY the current y position (optional, this just makes it so we
21390 * don't have to look it up again)
21392 cachePosition: function(iPageX, iPageY) {
21394 this.lastPageX = iPageX;
21395 this.lastPageY = iPageY;
21397 var aCoord = Roo.lib.Dom.getXY(this.getEl());
21398 this.lastPageX = aCoord[0];
21399 this.lastPageY = aCoord[1];
21404 * Auto-scroll the window if the dragged object has been moved beyond the
21405 * visible window boundary.
21406 * @method autoScroll
21407 * @param {int} x the drag element's x position
21408 * @param {int} y the drag element's y position
21409 * @param {int} h the height of the drag element
21410 * @param {int} w the width of the drag element
21413 autoScroll: function(x, y, h, w) {
21416 // The client height
21417 var clientH = Roo.lib.Dom.getViewWidth();
21419 // The client width
21420 var clientW = Roo.lib.Dom.getViewHeight();
21422 // The amt scrolled down
21423 var st = this.DDM.getScrollTop();
21425 // The amt scrolled right
21426 var sl = this.DDM.getScrollLeft();
21428 // Location of the bottom of the element
21431 // Location of the right of the element
21434 // The distance from the cursor to the bottom of the visible area,
21435 // adjusted so that we don't scroll if the cursor is beyond the
21436 // element drag constraints
21437 var toBot = (clientH + st - y - this.deltaY);
21439 // The distance from the cursor to the right of the visible area
21440 var toRight = (clientW + sl - x - this.deltaX);
21443 // How close to the edge the cursor must be before we scroll
21444 // var thresh = (document.all) ? 100 : 40;
21447 // How many pixels to scroll per autoscroll op. This helps to reduce
21448 // clunky scrolling. IE is more sensitive about this ... it needs this
21449 // value to be higher.
21450 var scrAmt = (document.all) ? 80 : 30;
21452 // Scroll down if we are near the bottom of the visible page and the
21453 // obj extends below the crease
21454 if ( bot > clientH && toBot < thresh ) {
21455 window.scrollTo(sl, st + scrAmt);
21458 // Scroll up if the window is scrolled down and the top of the object
21459 // goes above the top border
21460 if ( y < st && st > 0 && y - st < thresh ) {
21461 window.scrollTo(sl, st - scrAmt);
21464 // Scroll right if the obj is beyond the right border and the cursor is
21465 // near the border.
21466 if ( right > clientW && toRight < thresh ) {
21467 window.scrollTo(sl + scrAmt, st);
21470 // Scroll left if the window has been scrolled to the right and the obj
21471 // extends past the left border
21472 if ( x < sl && sl > 0 && x - sl < thresh ) {
21473 window.scrollTo(sl - scrAmt, st);
21479 * Finds the location the element should be placed if we want to move
21480 * it to where the mouse location less the click offset would place us.
21481 * @method getTargetCoord
21482 * @param {int} iPageX the X coordinate of the click
21483 * @param {int} iPageY the Y coordinate of the click
21484 * @return an object that contains the coordinates (Object.x and Object.y)
21487 getTargetCoord: function(iPageX, iPageY) {
21490 var x = iPageX - this.deltaX;
21491 var y = iPageY - this.deltaY;
21493 if (this.constrainX) {
21494 if (x < this.minX) { x = this.minX; }
21495 if (x > this.maxX) { x = this.maxX; }
21498 if (this.constrainY) {
21499 if (y < this.minY) { y = this.minY; }
21500 if (y > this.maxY) { y = this.maxY; }
21503 x = this.getTick(x, this.xTicks);
21504 y = this.getTick(y, this.yTicks);
21511 * Sets up config options specific to this class. Overrides
21512 * Roo.dd.DragDrop, but all versions of this method through the
21513 * inheritance chain are called
21515 applyConfig: function() {
21516 Roo.dd.DD.superclass.applyConfig.call(this);
21517 this.scroll = (this.config.scroll !== false);
21521 * Event that fires prior to the onMouseDown event. Overrides
21524 b4MouseDown: function(e) {
21525 // this.resetConstraints();
21526 this.autoOffset(e.getPageX(),
21531 * Event that fires prior to the onDrag event. Overrides
21534 b4Drag: function(e) {
21535 this.setDragElPos(e.getPageX(),
21539 toString: function() {
21540 return ("DD " + this.id);
21543 //////////////////////////////////////////////////////////////////////////
21544 // Debugging ygDragDrop events that can be overridden
21545 //////////////////////////////////////////////////////////////////////////
21547 startDrag: function(x, y) {
21550 onDrag: function(e) {
21553 onDragEnter: function(e, id) {
21556 onDragOver: function(e, id) {
21559 onDragOut: function(e, id) {
21562 onDragDrop: function(e, id) {
21565 endDrag: function(e) {
21572 * Ext JS Library 1.1.1
21573 * Copyright(c) 2006-2007, Ext JS, LLC.
21575 * Originally Released Under LGPL - original licence link has changed is not relivant.
21578 * <script type="text/javascript">
21582 * @class Roo.dd.DDProxy
21583 * A DragDrop implementation that inserts an empty, bordered div into
21584 * the document that follows the cursor during drag operations. At the time of
21585 * the click, the frame div is resized to the dimensions of the linked html
21586 * element, and moved to the exact location of the linked element.
21588 * References to the "frame" element refer to the single proxy element that
21589 * was created to be dragged in place of all DDProxy elements on the
21592 * @extends Roo.dd.DD
21594 * @param {String} id the id of the linked html element
21595 * @param {String} sGroup the group of related DragDrop objects
21596 * @param {object} config an object containing configurable attributes
21597 * Valid properties for DDProxy in addition to those in DragDrop:
21598 * resizeFrame, centerFrame, dragElId
21600 Roo.dd.DDProxy = function(id, sGroup, config) {
21602 this.init(id, sGroup, config);
21608 * The default drag frame div id
21609 * @property Roo.dd.DDProxy.dragElId
21613 Roo.dd.DDProxy.dragElId = "ygddfdiv";
21615 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
21618 * By default we resize the drag frame to be the same size as the element
21619 * we want to drag (this is to get the frame effect). We can turn it off
21620 * if we want a different behavior.
21621 * @property resizeFrame
21627 * By default the frame is positioned exactly where the drag element is, so
21628 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
21629 * you do not have constraints on the obj is to have the drag frame centered
21630 * around the cursor. Set centerFrame to true for this effect.
21631 * @property centerFrame
21634 centerFrame: false,
21637 * Creates the proxy element if it does not yet exist
21638 * @method createFrame
21640 createFrame: function() {
21642 var body = document.body;
21644 if (!body || !body.firstChild) {
21645 setTimeout( function() { self.createFrame(); }, 50 );
21649 var div = this.getDragEl();
21652 div = document.createElement("div");
21653 div.id = this.dragElId;
21656 s.position = "absolute";
21657 s.visibility = "hidden";
21659 s.border = "2px solid #aaa";
21662 // appendChild can blow up IE if invoked prior to the window load event
21663 // while rendering a table. It is possible there are other scenarios
21664 // that would cause this to happen as well.
21665 body.insertBefore(div, body.firstChild);
21670 * Initialization for the drag frame element. Must be called in the
21671 * constructor of all subclasses
21672 * @method initFrame
21674 initFrame: function() {
21675 this.createFrame();
21678 applyConfig: function() {
21679 Roo.dd.DDProxy.superclass.applyConfig.call(this);
21681 this.resizeFrame = (this.config.resizeFrame !== false);
21682 this.centerFrame = (this.config.centerFrame);
21683 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
21687 * Resizes the drag frame to the dimensions of the clicked object, positions
21688 * it over the object, and finally displays it
21689 * @method showFrame
21690 * @param {int} iPageX X click position
21691 * @param {int} iPageY Y click position
21694 showFrame: function(iPageX, iPageY) {
21695 var el = this.getEl();
21696 var dragEl = this.getDragEl();
21697 var s = dragEl.style;
21699 this._resizeProxy();
21701 if (this.centerFrame) {
21702 this.setDelta( Math.round(parseInt(s.width, 10)/2),
21703 Math.round(parseInt(s.height, 10)/2) );
21706 this.setDragElPos(iPageX, iPageY);
21708 Roo.fly(dragEl).show();
21712 * The proxy is automatically resized to the dimensions of the linked
21713 * element when a drag is initiated, unless resizeFrame is set to false
21714 * @method _resizeProxy
21717 _resizeProxy: function() {
21718 if (this.resizeFrame) {
21719 var el = this.getEl();
21720 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
21724 // overrides Roo.dd.DragDrop
21725 b4MouseDown: function(e) {
21726 var x = e.getPageX();
21727 var y = e.getPageY();
21728 this.autoOffset(x, y);
21729 this.setDragElPos(x, y);
21732 // overrides Roo.dd.DragDrop
21733 b4StartDrag: function(x, y) {
21734 // show the drag frame
21735 this.showFrame(x, y);
21738 // overrides Roo.dd.DragDrop
21739 b4EndDrag: function(e) {
21740 Roo.fly(this.getDragEl()).hide();
21743 // overrides Roo.dd.DragDrop
21744 // By default we try to move the element to the last location of the frame.
21745 // This is so that the default behavior mirrors that of Roo.dd.DD.
21746 endDrag: function(e) {
21748 var lel = this.getEl();
21749 var del = this.getDragEl();
21751 // Show the drag frame briefly so we can get its position
21752 del.style.visibility = "";
21755 // Hide the linked element before the move to get around a Safari
21757 lel.style.visibility = "hidden";
21758 Roo.dd.DDM.moveToEl(lel, del);
21759 del.style.visibility = "hidden";
21760 lel.style.visibility = "";
21765 beforeMove : function(){
21769 afterDrag : function(){
21773 toString: function() {
21774 return ("DDProxy " + this.id);
21780 * Ext JS Library 1.1.1
21781 * Copyright(c) 2006-2007, Ext JS, LLC.
21783 * Originally Released Under LGPL - original licence link has changed is not relivant.
21786 * <script type="text/javascript">
21790 * @class Roo.dd.DDTarget
21791 * A DragDrop implementation that does not move, but can be a drop
21792 * target. You would get the same result by simply omitting implementation
21793 * for the event callbacks, but this way we reduce the processing cost of the
21794 * event listener and the callbacks.
21795 * @extends Roo.dd.DragDrop
21797 * @param {String} id the id of the element that is a drop target
21798 * @param {String} sGroup the group of related DragDrop objects
21799 * @param {object} config an object containing configurable attributes
21800 * Valid properties for DDTarget in addition to those in
21804 Roo.dd.DDTarget = function(id, sGroup, config) {
21806 this.initTarget(id, sGroup, config);
21808 if (config && (config.listeners || config.events)) {
21809 Roo.dd.DragDrop.superclass.constructor.call(this, {
21810 listeners : config.listeners || {},
21811 events : config.events || {}
21816 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
21817 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
21818 toString: function() {
21819 return ("DDTarget " + this.id);
21824 * Ext JS Library 1.1.1
21825 * Copyright(c) 2006-2007, Ext JS, LLC.
21827 * Originally Released Under LGPL - original licence link has changed is not relivant.
21830 * <script type="text/javascript">
21835 * @class Roo.dd.ScrollManager
21836 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
21837 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
21840 Roo.dd.ScrollManager = function(){
21841 var ddm = Roo.dd.DragDropMgr;
21848 var onStop = function(e){
21853 var triggerRefresh = function(){
21854 if(ddm.dragCurrent){
21855 ddm.refreshCache(ddm.dragCurrent.groups);
21859 var doScroll = function(){
21860 if(ddm.dragCurrent){
21861 var dds = Roo.dd.ScrollManager;
21863 if(proc.el.scroll(proc.dir, dds.increment)){
21867 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
21872 var clearProc = function(){
21874 clearInterval(proc.id);
21881 var startProc = function(el, dir){
21882 Roo.log('scroll startproc');
21886 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
21889 var onFire = function(e, isDrop){
21891 if(isDrop || !ddm.dragCurrent){ return; }
21892 var dds = Roo.dd.ScrollManager;
21893 if(!dragEl || dragEl != ddm.dragCurrent){
21894 dragEl = ddm.dragCurrent;
21895 // refresh regions on drag start
21896 dds.refreshCache();
21899 var xy = Roo.lib.Event.getXY(e);
21900 var pt = new Roo.lib.Point(xy[0], xy[1]);
21901 for(var id in els){
21902 var el = els[id], r = el._region;
21903 if(r && r.contains(pt) && el.isScrollable()){
21904 if(r.bottom - pt.y <= dds.thresh){
21906 startProc(el, "down");
21909 }else if(r.right - pt.x <= dds.thresh){
21911 startProc(el, "left");
21914 }else if(pt.y - r.top <= dds.thresh){
21916 startProc(el, "up");
21919 }else if(pt.x - r.left <= dds.thresh){
21921 startProc(el, "right");
21930 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
21931 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
21935 * Registers new overflow element(s) to auto scroll
21936 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
21938 register : function(el){
21939 if(el instanceof Array){
21940 for(var i = 0, len = el.length; i < len; i++) {
21941 this.register(el[i]);
21947 Roo.dd.ScrollManager.els = els;
21951 * Unregisters overflow element(s) so they are no longer scrolled
21952 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
21954 unregister : function(el){
21955 if(el instanceof Array){
21956 for(var i = 0, len = el.length; i < len; i++) {
21957 this.unregister(el[i]);
21966 * The number of pixels from the edge of a container the pointer needs to be to
21967 * trigger scrolling (defaults to 25)
21973 * The number of pixels to scroll in each scroll increment (defaults to 50)
21979 * The frequency of scrolls in milliseconds (defaults to 500)
21985 * True to animate the scroll (defaults to true)
21991 * The animation duration in seconds -
21992 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
21998 * Manually trigger a cache refresh.
22000 refreshCache : function(){
22001 for(var id in els){
22002 if(typeof els[id] == 'object'){ // for people extending the object prototype
22003 els[id]._region = els[id].getRegion();
22010 * Ext JS Library 1.1.1
22011 * Copyright(c) 2006-2007, Ext JS, LLC.
22013 * Originally Released Under LGPL - original licence link has changed is not relivant.
22016 * <script type="text/javascript">
22021 * @class Roo.dd.Registry
22022 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
22023 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
22026 Roo.dd.Registry = function(){
22029 var autoIdSeed = 0;
22031 var getId = function(el, autogen){
22032 if(typeof el == "string"){
22036 if(!id && autogen !== false){
22037 id = "roodd-" + (++autoIdSeed);
22045 * Register a drag drop element
22046 * @param {String|HTMLElement} element The id or DOM node to register
22047 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
22048 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
22049 * knows how to interpret, plus there are some specific properties known to the Registry that should be
22050 * populated in the data object (if applicable):
22052 Value Description<br />
22053 --------- ------------------------------------------<br />
22054 handles Array of DOM nodes that trigger dragging<br />
22055 for the element being registered<br />
22056 isHandle True if the element passed in triggers<br />
22057 dragging itself, else false
22060 register : function(el, data){
22062 if(typeof el == "string"){
22063 el = document.getElementById(el);
22066 elements[getId(el)] = data;
22067 if(data.isHandle !== false){
22068 handles[data.ddel.id] = data;
22071 var hs = data.handles;
22072 for(var i = 0, len = hs.length; i < len; i++){
22073 handles[getId(hs[i])] = data;
22079 * Unregister a drag drop element
22080 * @param {String|HTMLElement} element The id or DOM node to unregister
22082 unregister : function(el){
22083 var id = getId(el, false);
22084 var data = elements[id];
22086 delete elements[id];
22088 var hs = data.handles;
22089 for(var i = 0, len = hs.length; i < len; i++){
22090 delete handles[getId(hs[i], false)];
22097 * Returns the handle registered for a DOM Node by id
22098 * @param {String|HTMLElement} id The DOM node or id to look up
22099 * @return {Object} handle The custom handle data
22101 getHandle : function(id){
22102 if(typeof id != "string"){ // must be element?
22105 return handles[id];
22109 * Returns the handle that is registered for the DOM node that is the target of the event
22110 * @param {Event} e The event
22111 * @return {Object} handle The custom handle data
22113 getHandleFromEvent : function(e){
22114 var t = Roo.lib.Event.getTarget(e);
22115 return t ? handles[t.id] : null;
22119 * Returns a custom data object that is registered for a DOM node by id
22120 * @param {String|HTMLElement} id The DOM node or id to look up
22121 * @return {Object} data The custom data
22123 getTarget : function(id){
22124 if(typeof id != "string"){ // must be element?
22127 return elements[id];
22131 * Returns a custom data object that is registered for the DOM node that is the target of the event
22132 * @param {Event} e The event
22133 * @return {Object} data The custom data
22135 getTargetFromEvent : function(e){
22136 var t = Roo.lib.Event.getTarget(e);
22137 return t ? elements[t.id] || handles[t.id] : null;
22142 * Ext JS Library 1.1.1
22143 * Copyright(c) 2006-2007, Ext JS, LLC.
22145 * Originally Released Under LGPL - original licence link has changed is not relivant.
22148 * <script type="text/javascript">
22153 * @class Roo.dd.StatusProxy
22154 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
22155 * default drag proxy used by all Roo.dd components.
22157 * @param {Object} config
22159 Roo.dd.StatusProxy = function(config){
22160 Roo.apply(this, config);
22161 this.id = this.id || Roo.id();
22162 this.el = new Roo.Layer({
22164 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
22165 {tag: "div", cls: "x-dd-drop-icon"},
22166 {tag: "div", cls: "x-dd-drag-ghost"}
22169 shadow: !config || config.shadow !== false
22171 this.ghost = Roo.get(this.el.dom.childNodes[1]);
22172 this.dropStatus = this.dropNotAllowed;
22175 Roo.dd.StatusProxy.prototype = {
22177 * @cfg {String} dropAllowed
22178 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
22180 dropAllowed : "x-dd-drop-ok",
22182 * @cfg {String} dropNotAllowed
22183 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
22185 dropNotAllowed : "x-dd-drop-nodrop",
22188 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
22189 * over the current target element.
22190 * @param {String} cssClass The css class for the new drop status indicator image
22192 setStatus : function(cssClass){
22193 cssClass = cssClass || this.dropNotAllowed;
22194 if(this.dropStatus != cssClass){
22195 this.el.replaceClass(this.dropStatus, cssClass);
22196 this.dropStatus = cssClass;
22201 * Resets the status indicator to the default dropNotAllowed value
22202 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
22204 reset : function(clearGhost){
22205 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
22206 this.dropStatus = this.dropNotAllowed;
22208 this.ghost.update("");
22213 * Updates the contents of the ghost element
22214 * @param {String} html The html that will replace the current innerHTML of the ghost element
22216 update : function(html){
22217 if(typeof html == "string"){
22218 this.ghost.update(html);
22220 this.ghost.update("");
22221 html.style.margin = "0";
22222 this.ghost.dom.appendChild(html);
22224 // ensure float = none set?? cant remember why though.
22225 var el = this.ghost.dom.firstChild;
22227 Roo.fly(el).setStyle('float', 'none');
22232 * Returns the underlying proxy {@link Roo.Layer}
22233 * @return {Roo.Layer} el
22235 getEl : function(){
22240 * Returns the ghost element
22241 * @return {Roo.Element} el
22243 getGhost : function(){
22249 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
22251 hide : function(clear){
22259 * Stops the repair animation if it's currently running
22262 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
22268 * Displays this proxy
22275 * Force the Layer to sync its shadow and shim positions to the element
22282 * Causes the proxy to return to its position of origin via an animation. Should be called after an
22283 * invalid drop operation by the item being dragged.
22284 * @param {Array} xy The XY position of the element ([x, y])
22285 * @param {Function} callback The function to call after the repair is complete
22286 * @param {Object} scope The scope in which to execute the callback
22288 repair : function(xy, callback, scope){
22289 this.callback = callback;
22290 this.scope = scope;
22291 if(xy && this.animRepair !== false){
22292 this.el.addClass("x-dd-drag-repair");
22293 this.el.hideUnders(true);
22294 this.anim = this.el.shift({
22295 duration: this.repairDuration || .5,
22299 callback: this.afterRepair,
22303 this.afterRepair();
22308 afterRepair : function(){
22310 if(typeof this.callback == "function"){
22311 this.callback.call(this.scope || this);
22313 this.callback = null;
22318 * Ext JS Library 1.1.1
22319 * Copyright(c) 2006-2007, Ext JS, LLC.
22321 * Originally Released Under LGPL - original licence link has changed is not relivant.
22324 * <script type="text/javascript">
22328 * @class Roo.dd.DragSource
22329 * @extends Roo.dd.DDProxy
22330 * A simple class that provides the basic implementation needed to make any element draggable.
22332 * @param {String/HTMLElement/Element} el The container element
22333 * @param {Object} config
22335 Roo.dd.DragSource = function(el, config){
22336 this.el = Roo.get(el);
22337 this.dragData = {};
22339 Roo.apply(this, config);
22342 this.proxy = new Roo.dd.StatusProxy();
22345 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
22346 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
22348 this.dragging = false;
22351 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
22353 * @cfg {String} dropAllowed
22354 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
22356 dropAllowed : "x-dd-drop-ok",
22358 * @cfg {String} dropNotAllowed
22359 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
22361 dropNotAllowed : "x-dd-drop-nodrop",
22364 * Returns the data object associated with this drag source
22365 * @return {Object} data An object containing arbitrary data
22367 getDragData : function(e){
22368 return this.dragData;
22372 onDragEnter : function(e, id){
22373 var target = Roo.dd.DragDropMgr.getDDById(id);
22374 this.cachedTarget = target;
22375 if(this.beforeDragEnter(target, e, id) !== false){
22376 if(target.isNotifyTarget){
22377 var status = target.notifyEnter(this, e, this.dragData);
22378 this.proxy.setStatus(status);
22380 this.proxy.setStatus(this.dropAllowed);
22383 if(this.afterDragEnter){
22385 * An empty function by default, but provided so that you can perform a custom action
22386 * when the dragged item enters the drop target by providing an implementation.
22387 * @param {Roo.dd.DragDrop} target The drop target
22388 * @param {Event} e The event object
22389 * @param {String} id The id of the dragged element
22390 * @method afterDragEnter
22392 this.afterDragEnter(target, e, id);
22398 * An empty function by default, but provided so that you can perform a custom action
22399 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
22400 * @param {Roo.dd.DragDrop} target The drop target
22401 * @param {Event} e The event object
22402 * @param {String} id The id of the dragged element
22403 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
22405 beforeDragEnter : function(target, e, id){
22410 alignElWithMouse: function() {
22411 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
22416 onDragOver : function(e, id){
22417 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
22418 if(this.beforeDragOver(target, e, id) !== false){
22419 if(target.isNotifyTarget){
22420 var status = target.notifyOver(this, e, this.dragData);
22421 this.proxy.setStatus(status);
22424 if(this.afterDragOver){
22426 * An empty function by default, but provided so that you can perform a custom action
22427 * while the dragged item is over the drop target by providing an implementation.
22428 * @param {Roo.dd.DragDrop} target The drop target
22429 * @param {Event} e The event object
22430 * @param {String} id The id of the dragged element
22431 * @method afterDragOver
22433 this.afterDragOver(target, e, id);
22439 * An empty function by default, but provided so that you can perform a custom action
22440 * while the dragged item is over the drop target and optionally cancel the onDragOver.
22441 * @param {Roo.dd.DragDrop} target The drop target
22442 * @param {Event} e The event object
22443 * @param {String} id The id of the dragged element
22444 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
22446 beforeDragOver : function(target, e, id){
22451 onDragOut : function(e, id){
22452 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
22453 if(this.beforeDragOut(target, e, id) !== false){
22454 if(target.isNotifyTarget){
22455 target.notifyOut(this, e, this.dragData);
22457 this.proxy.reset();
22458 if(this.afterDragOut){
22460 * An empty function by default, but provided so that you can perform a custom action
22461 * after the dragged item is dragged out of the target without dropping.
22462 * @param {Roo.dd.DragDrop} target The drop target
22463 * @param {Event} e The event object
22464 * @param {String} id The id of the dragged element
22465 * @method afterDragOut
22467 this.afterDragOut(target, e, id);
22470 this.cachedTarget = null;
22474 * An empty function by default, but provided so that you can perform a custom action before the dragged
22475 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
22476 * @param {Roo.dd.DragDrop} target The drop target
22477 * @param {Event} e The event object
22478 * @param {String} id The id of the dragged element
22479 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
22481 beforeDragOut : function(target, e, id){
22486 onDragDrop : function(e, id){
22487 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
22488 if(this.beforeDragDrop(target, e, id) !== false){
22489 if(target.isNotifyTarget){
22490 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
22491 this.onValidDrop(target, e, id);
22493 this.onInvalidDrop(target, e, id);
22496 this.onValidDrop(target, e, id);
22499 if(this.afterDragDrop){
22501 * An empty function by default, but provided so that you can perform a custom action
22502 * after a valid drag drop has occurred by providing an implementation.
22503 * @param {Roo.dd.DragDrop} target The drop target
22504 * @param {Event} e The event object
22505 * @param {String} id The id of the dropped element
22506 * @method afterDragDrop
22508 this.afterDragDrop(target, e, id);
22511 delete this.cachedTarget;
22515 * An empty function by default, but provided so that you can perform a custom action before the dragged
22516 * item is dropped onto the target and optionally cancel the onDragDrop.
22517 * @param {Roo.dd.DragDrop} target The drop target
22518 * @param {Event} e The event object
22519 * @param {String} id The id of the dragged element
22520 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
22522 beforeDragDrop : function(target, e, id){
22527 onValidDrop : function(target, e, id){
22529 if(this.afterValidDrop){
22531 * An empty function by default, but provided so that you can perform a custom action
22532 * after a valid drop has occurred by providing an implementation.
22533 * @param {Object} target The target DD
22534 * @param {Event} e The event object
22535 * @param {String} id The id of the dropped element
22536 * @method afterInvalidDrop
22538 this.afterValidDrop(target, e, id);
22543 getRepairXY : function(e, data){
22544 return this.el.getXY();
22548 onInvalidDrop : function(target, e, id){
22549 this.beforeInvalidDrop(target, e, id);
22550 if(this.cachedTarget){
22551 if(this.cachedTarget.isNotifyTarget){
22552 this.cachedTarget.notifyOut(this, e, this.dragData);
22554 this.cacheTarget = null;
22556 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
22558 if(this.afterInvalidDrop){
22560 * An empty function by default, but provided so that you can perform a custom action
22561 * after an invalid drop has occurred by providing an implementation.
22562 * @param {Event} e The event object
22563 * @param {String} id The id of the dropped element
22564 * @method afterInvalidDrop
22566 this.afterInvalidDrop(e, id);
22571 afterRepair : function(){
22573 this.el.highlight(this.hlColor || "c3daf9");
22575 this.dragging = false;
22579 * An empty function by default, but provided so that you can perform a custom action after an invalid
22580 * drop has occurred.
22581 * @param {Roo.dd.DragDrop} target The drop target
22582 * @param {Event} e The event object
22583 * @param {String} id The id of the dragged element
22584 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
22586 beforeInvalidDrop : function(target, e, id){
22591 handleMouseDown : function(e){
22592 if(this.dragging) {
22595 var data = this.getDragData(e);
22596 if(data && this.onBeforeDrag(data, e) !== false){
22597 this.dragData = data;
22599 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
22604 * An empty function by default, but provided so that you can perform a custom action before the initial
22605 * drag event begins and optionally cancel it.
22606 * @param {Object} data An object containing arbitrary data to be shared with drop targets
22607 * @param {Event} e The event object
22608 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
22610 onBeforeDrag : function(data, e){
22615 * An empty function by default, but provided so that you can perform a custom action once the initial
22616 * drag event has begun. The drag cannot be canceled from this function.
22617 * @param {Number} x The x position of the click on the dragged object
22618 * @param {Number} y The y position of the click on the dragged object
22620 onStartDrag : Roo.emptyFn,
22622 // private - YUI override
22623 startDrag : function(x, y){
22624 this.proxy.reset();
22625 this.dragging = true;
22626 this.proxy.update("");
22627 this.onInitDrag(x, y);
22632 onInitDrag : function(x, y){
22633 var clone = this.el.dom.cloneNode(true);
22634 clone.id = Roo.id(); // prevent duplicate ids
22635 this.proxy.update(clone);
22636 this.onStartDrag(x, y);
22641 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
22642 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
22644 getProxy : function(){
22649 * Hides the drag source's {@link Roo.dd.StatusProxy}
22651 hideProxy : function(){
22653 this.proxy.reset(true);
22654 this.dragging = false;
22658 triggerCacheRefresh : function(){
22659 Roo.dd.DDM.refreshCache(this.groups);
22662 // private - override to prevent hiding
22663 b4EndDrag: function(e) {
22666 // private - override to prevent moving
22667 endDrag : function(e){
22668 this.onEndDrag(this.dragData, e);
22672 onEndDrag : function(data, e){
22675 // private - pin to cursor
22676 autoOffset : function(x, y) {
22677 this.setDelta(-12, -20);
22681 * Ext JS Library 1.1.1
22682 * Copyright(c) 2006-2007, Ext JS, LLC.
22684 * Originally Released Under LGPL - original licence link has changed is not relivant.
22687 * <script type="text/javascript">
22692 * @class Roo.dd.DropTarget
22693 * @extends Roo.dd.DDTarget
22694 * A simple class that provides the basic implementation needed to make any element a drop target that can have
22695 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
22697 * @param {String/HTMLElement/Element} el The container element
22698 * @param {Object} config
22700 Roo.dd.DropTarget = function(el, config){
22701 this.el = Roo.get(el);
22703 var listeners = false; ;
22704 if (config && config.listeners) {
22705 listeners= config.listeners;
22706 delete config.listeners;
22708 Roo.apply(this, config);
22710 if(this.containerScroll){
22711 Roo.dd.ScrollManager.register(this.el);
22715 * @scope Roo.dd.DropTarget
22720 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
22721 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
22722 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
22724 * IMPORTANT : it should set this.valid to true|false
22726 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22727 * @param {Event} e The event
22728 * @param {Object} data An object containing arbitrary data supplied by the drag source
22734 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
22735 * This method will be called on every mouse movement while the drag source is over the drop target.
22736 * This default implementation simply returns the dropAllowed config value.
22738 * IMPORTANT : it should set this.valid to true|false
22740 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22741 * @param {Event} e The event
22742 * @param {Object} data An object containing arbitrary data supplied by the drag source
22748 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
22749 * out of the target without dropping. This default implementation simply removes the CSS class specified by
22750 * overClass (if any) from the drop element.
22753 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22754 * @param {Event} e The event
22755 * @param {Object} data An object containing arbitrary data supplied by the drag source
22761 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
22762 * been dropped on it. This method has no default implementation and returns false, so you must provide an
22763 * implementation that does something to process the drop event and returns true so that the drag source's
22764 * repair action does not run.
22766 * IMPORTANT : it should set this.success
22768 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22769 * @param {Event} e The event
22770 * @param {Object} data An object containing arbitrary data supplied by the drag source
22776 Roo.dd.DropTarget.superclass.constructor.call( this,
22778 this.ddGroup || this.group,
22781 listeners : listeners || {}
22789 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
22791 * @cfg {String} overClass
22792 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
22795 * @cfg {String} ddGroup
22796 * The drag drop group to handle drop events for
22800 * @cfg {String} dropAllowed
22801 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
22803 dropAllowed : "x-dd-drop-ok",
22805 * @cfg {String} dropNotAllowed
22806 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
22808 dropNotAllowed : "x-dd-drop-nodrop",
22810 * @cfg {boolean} success
22811 * set this after drop listener..
22815 * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
22816 * if the drop point is valid for over/enter..
22823 isNotifyTarget : true,
22828 notifyEnter : function(dd, e, data)
22831 this.fireEvent('enter', dd, e, data);
22832 if(this.overClass){
22833 this.el.addClass(this.overClass);
22835 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
22836 this.valid ? this.dropAllowed : this.dropNotAllowed
22843 notifyOver : function(dd, e, data)
22846 this.fireEvent('over', dd, e, data);
22847 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
22848 this.valid ? this.dropAllowed : this.dropNotAllowed
22855 notifyOut : function(dd, e, data)
22857 this.fireEvent('out', dd, e, data);
22858 if(this.overClass){
22859 this.el.removeClass(this.overClass);
22866 notifyDrop : function(dd, e, data)
22868 this.success = false;
22869 this.fireEvent('drop', dd, e, data);
22870 return this.success;
22874 * Ext JS Library 1.1.1
22875 * Copyright(c) 2006-2007, Ext JS, LLC.
22877 * Originally Released Under LGPL - original licence link has changed is not relivant.
22880 * <script type="text/javascript">
22885 * @class Roo.dd.DragZone
22886 * @extends Roo.dd.DragSource
22887 * This class provides a container DD instance that proxies for multiple child node sources.<br />
22888 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
22890 * @param {String/HTMLElement/Element} el The container element
22891 * @param {Object} config
22893 Roo.dd.DragZone = function(el, config){
22894 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
22895 if(this.containerScroll){
22896 Roo.dd.ScrollManager.register(this.el);
22900 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
22902 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
22903 * for auto scrolling during drag operations.
22906 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
22907 * method after a failed drop (defaults to "c3daf9" - light blue)
22911 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
22912 * for a valid target to drag based on the mouse down. Override this method
22913 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
22914 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
22915 * @param {EventObject} e The mouse down event
22916 * @return {Object} The dragData
22918 getDragData : function(e){
22919 return Roo.dd.Registry.getHandleFromEvent(e);
22923 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
22924 * this.dragData.ddel
22925 * @param {Number} x The x position of the click on the dragged object
22926 * @param {Number} y The y position of the click on the dragged object
22927 * @return {Boolean} true to continue the drag, false to cancel
22929 onInitDrag : function(x, y){
22930 this.proxy.update(this.dragData.ddel.cloneNode(true));
22931 this.onStartDrag(x, y);
22936 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
22938 afterRepair : function(){
22940 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
22942 this.dragging = false;
22946 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
22947 * the XY of this.dragData.ddel
22948 * @param {EventObject} e The mouse up event
22949 * @return {Array} The xy location (e.g. [100, 200])
22951 getRepairXY : function(e){
22952 return Roo.Element.fly(this.dragData.ddel).getXY();
22956 * Ext JS Library 1.1.1
22957 * Copyright(c) 2006-2007, Ext JS, LLC.
22959 * Originally Released Under LGPL - original licence link has changed is not relivant.
22962 * <script type="text/javascript">
22965 * @class Roo.dd.DropZone
22966 * @extends Roo.dd.DropTarget
22967 * This class provides a container DD instance that proxies for multiple child node targets.<br />
22968 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
22970 * @param {String/HTMLElement/Element} el The container element
22971 * @param {Object} config
22973 Roo.dd.DropZone = function(el, config){
22974 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
22977 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
22979 * Returns a custom data object associated with the DOM node that is the target of the event. By default
22980 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
22981 * provide your own custom lookup.
22982 * @param {Event} e The event
22983 * @return {Object} data The custom data
22985 getTargetFromEvent : function(e){
22986 return Roo.dd.Registry.getTargetFromEvent(e);
22990 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
22991 * that it has registered. This method has no default implementation and should be overridden to provide
22992 * node-specific processing if necessary.
22993 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22994 * {@link #getTargetFromEvent} for this node)
22995 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22996 * @param {Event} e The event
22997 * @param {Object} data An object containing arbitrary data supplied by the drag source
22999 onNodeEnter : function(n, dd, e, data){
23004 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
23005 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
23006 * overridden to provide the proper feedback.
23007 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
23008 * {@link #getTargetFromEvent} for this node)
23009 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23010 * @param {Event} e The event
23011 * @param {Object} data An object containing arbitrary data supplied by the drag source
23012 * @return {String} status The CSS class that communicates the drop status back to the source so that the
23013 * underlying {@link Roo.dd.StatusProxy} can be updated
23015 onNodeOver : function(n, dd, e, data){
23016 return this.dropAllowed;
23020 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
23021 * the drop node without dropping. This method has no default implementation and should be overridden to provide
23022 * node-specific processing if necessary.
23023 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
23024 * {@link #getTargetFromEvent} for this node)
23025 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23026 * @param {Event} e The event
23027 * @param {Object} data An object containing arbitrary data supplied by the drag source
23029 onNodeOut : function(n, dd, e, data){
23034 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
23035 * the drop node. The default implementation returns false, so it should be overridden to provide the
23036 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
23037 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
23038 * {@link #getTargetFromEvent} for this node)
23039 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23040 * @param {Event} e The event
23041 * @param {Object} data An object containing arbitrary data supplied by the drag source
23042 * @return {Boolean} True if the drop was valid, else false
23044 onNodeDrop : function(n, dd, e, data){
23049 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
23050 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
23051 * it should be overridden to provide the proper feedback if necessary.
23052 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23053 * @param {Event} e The event
23054 * @param {Object} data An object containing arbitrary data supplied by the drag source
23055 * @return {String} status The CSS class that communicates the drop status back to the source so that the
23056 * underlying {@link Roo.dd.StatusProxy} can be updated
23058 onContainerOver : function(dd, e, data){
23059 return this.dropNotAllowed;
23063 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
23064 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
23065 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
23066 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
23067 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23068 * @param {Event} e The event
23069 * @param {Object} data An object containing arbitrary data supplied by the drag source
23070 * @return {Boolean} True if the drop was valid, else false
23072 onContainerDrop : function(dd, e, data){
23077 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
23078 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
23079 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
23080 * you should override this method and provide a custom implementation.
23081 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23082 * @param {Event} e The event
23083 * @param {Object} data An object containing arbitrary data supplied by the drag source
23084 * @return {String} status The CSS class that communicates the drop status back to the source so that the
23085 * underlying {@link Roo.dd.StatusProxy} can be updated
23087 notifyEnter : function(dd, e, data){
23088 return this.dropNotAllowed;
23092 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
23093 * This method will be called on every mouse movement while the drag source is over the drop zone.
23094 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
23095 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
23096 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
23097 * registered node, it will call {@link #onContainerOver}.
23098 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23099 * @param {Event} e The event
23100 * @param {Object} data An object containing arbitrary data supplied by the drag source
23101 * @return {String} status The CSS class that communicates the drop status back to the source so that the
23102 * underlying {@link Roo.dd.StatusProxy} can be updated
23104 notifyOver : function(dd, e, data){
23105 var n = this.getTargetFromEvent(e);
23106 if(!n){ // not over valid drop target
23107 if(this.lastOverNode){
23108 this.onNodeOut(this.lastOverNode, dd, e, data);
23109 this.lastOverNode = null;
23111 return this.onContainerOver(dd, e, data);
23113 if(this.lastOverNode != n){
23114 if(this.lastOverNode){
23115 this.onNodeOut(this.lastOverNode, dd, e, data);
23117 this.onNodeEnter(n, dd, e, data);
23118 this.lastOverNode = n;
23120 return this.onNodeOver(n, dd, e, data);
23124 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
23125 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
23126 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
23127 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
23128 * @param {Event} e The event
23129 * @param {Object} data An object containing arbitrary data supplied by the drag zone
23131 notifyOut : function(dd, e, data){
23132 if(this.lastOverNode){
23133 this.onNodeOut(this.lastOverNode, dd, e, data);
23134 this.lastOverNode = null;
23139 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
23140 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
23141 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
23142 * otherwise it will call {@link #onContainerDrop}.
23143 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23144 * @param {Event} e The event
23145 * @param {Object} data An object containing arbitrary data supplied by the drag source
23146 * @return {Boolean} True if the drop was valid, else false
23148 notifyDrop : function(dd, e, data){
23149 if(this.lastOverNode){
23150 this.onNodeOut(this.lastOverNode, dd, e, data);
23151 this.lastOverNode = null;
23153 var n = this.getTargetFromEvent(e);
23155 this.onNodeDrop(n, dd, e, data) :
23156 this.onContainerDrop(dd, e, data);
23160 triggerCacheRefresh : function(){
23161 Roo.dd.DDM.refreshCache(this.groups);
23165 * Ext JS Library 1.1.1
23166 * Copyright(c) 2006-2007, Ext JS, LLC.
23168 * Originally Released Under LGPL - original licence link has changed is not relivant.
23171 * <script type="text/javascript">
23176 * @class Roo.data.SortTypes
23178 * Defines the default sorting (casting?) comparison functions used when sorting data.
23180 Roo.data.SortTypes = {
23182 * Default sort that does nothing
23183 * @param {Mixed} s The value being converted
23184 * @return {Mixed} The comparison value
23186 none : function(s){
23191 * The regular expression used to strip tags
23195 stripTagsRE : /<\/?[^>]+>/gi,
23198 * Strips all HTML tags to sort on text only
23199 * @param {Mixed} s The value being converted
23200 * @return {String} The comparison value
23202 asText : function(s){
23203 return String(s).replace(this.stripTagsRE, "");
23207 * Strips all HTML tags to sort on text only - Case insensitive
23208 * @param {Mixed} s The value being converted
23209 * @return {String} The comparison value
23211 asUCText : function(s){
23212 return String(s).toUpperCase().replace(this.stripTagsRE, "");
23216 * Case insensitive string
23217 * @param {Mixed} s The value being converted
23218 * @return {String} The comparison value
23220 asUCString : function(s) {
23221 return String(s).toUpperCase();
23226 * @param {Mixed} s The value being converted
23227 * @return {Number} The comparison value
23229 asDate : function(s) {
23233 if(s instanceof Date){
23234 return s.getTime();
23236 return Date.parse(String(s));
23241 * @param {Mixed} s The value being converted
23242 * @return {Float} The comparison value
23244 asFloat : function(s) {
23245 var val = parseFloat(String(s).replace(/,/g, ""));
23254 * @param {Mixed} s The value being converted
23255 * @return {Number} The comparison value
23257 asInt : function(s) {
23258 var val = parseInt(String(s).replace(/,/g, ""));
23266 * Ext JS Library 1.1.1
23267 * Copyright(c) 2006-2007, Ext JS, LLC.
23269 * Originally Released Under LGPL - original licence link has changed is not relivant.
23272 * <script type="text/javascript">
23276 * @class Roo.data.Record
23277 * Instances of this class encapsulate both record <em>definition</em> information, and record
23278 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
23279 * to access Records cached in an {@link Roo.data.Store} object.<br>
23281 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
23282 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
23285 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
23287 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
23288 * {@link #create}. The parameters are the same.
23289 * @param {Array} data An associative Array of data values keyed by the field name.
23290 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
23291 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
23292 * not specified an integer id is generated.
23294 Roo.data.Record = function(data, id){
23295 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
23300 * Generate a constructor for a specific record layout.
23301 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
23302 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
23303 * Each field definition object may contain the following properties: <ul>
23304 * <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,
23305 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
23306 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
23307 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
23308 * is being used, then this is a string containing the javascript expression to reference the data relative to
23309 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
23310 * to the data item relative to the record element. If the mapping expression is the same as the field name,
23311 * this may be omitted.</p></li>
23312 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
23313 * <ul><li>auto (Default, implies no conversion)</li>
23318 * <li>date</li></ul></p></li>
23319 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
23320 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
23321 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
23322 * by the Reader into an object that will be stored in the Record. It is passed the
23323 * following parameters:<ul>
23324 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
23326 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
23328 * <br>usage:<br><pre><code>
23329 var TopicRecord = Roo.data.Record.create(
23330 {name: 'title', mapping: 'topic_title'},
23331 {name: 'author', mapping: 'username'},
23332 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
23333 {name: 'lastPost', mapping: 'post_time', type: 'date'},
23334 {name: 'lastPoster', mapping: 'user2'},
23335 {name: 'excerpt', mapping: 'post_text'}
23338 var myNewRecord = new TopicRecord({
23339 title: 'Do my job please',
23342 lastPost: new Date(),
23343 lastPoster: 'Animal',
23344 excerpt: 'No way dude!'
23346 myStore.add(myNewRecord);
23351 Roo.data.Record.create = function(o){
23352 var f = function(){
23353 f.superclass.constructor.apply(this, arguments);
23355 Roo.extend(f, Roo.data.Record);
23356 var p = f.prototype;
23357 p.fields = new Roo.util.MixedCollection(false, function(field){
23360 for(var i = 0, len = o.length; i < len; i++){
23361 p.fields.add(new Roo.data.Field(o[i]));
23363 f.getField = function(name){
23364 return p.fields.get(name);
23369 Roo.data.Record.AUTO_ID = 1000;
23370 Roo.data.Record.EDIT = 'edit';
23371 Roo.data.Record.REJECT = 'reject';
23372 Roo.data.Record.COMMIT = 'commit';
23374 Roo.data.Record.prototype = {
23376 * Readonly flag - true if this record has been modified.
23385 join : function(store){
23386 this.store = store;
23390 * Set the named field to the specified value.
23391 * @param {String} name The name of the field to set.
23392 * @param {Object} value The value to set the field to.
23394 set : function(name, value){
23395 if(this.data[name] == value){
23399 if(!this.modified){
23400 this.modified = {};
23402 if(typeof this.modified[name] == 'undefined'){
23403 this.modified[name] = this.data[name];
23405 this.data[name] = value;
23406 if(!this.editing && this.store){
23407 this.store.afterEdit(this);
23412 * Get the value of the named field.
23413 * @param {String} name The name of the field to get the value of.
23414 * @return {Object} The value of the field.
23416 get : function(name){
23417 return this.data[name];
23421 beginEdit : function(){
23422 this.editing = true;
23423 this.modified = {};
23427 cancelEdit : function(){
23428 this.editing = false;
23429 delete this.modified;
23433 endEdit : function(){
23434 this.editing = false;
23435 if(this.dirty && this.store){
23436 this.store.afterEdit(this);
23441 * Usually called by the {@link Roo.data.Store} which owns the Record.
23442 * Rejects all changes made to the Record since either creation, or the last commit operation.
23443 * Modified fields are reverted to their original values.
23445 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
23446 * of reject operations.
23448 reject : function(){
23449 var m = this.modified;
23451 if(typeof m[n] != "function"){
23452 this.data[n] = m[n];
23455 this.dirty = false;
23456 delete this.modified;
23457 this.editing = false;
23459 this.store.afterReject(this);
23464 * Usually called by the {@link Roo.data.Store} which owns the Record.
23465 * Commits all changes made to the Record since either creation, or the last commit operation.
23467 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
23468 * of commit operations.
23470 commit : function(){
23471 this.dirty = false;
23472 delete this.modified;
23473 this.editing = false;
23475 this.store.afterCommit(this);
23480 hasError : function(){
23481 return this.error != null;
23485 clearError : function(){
23490 * Creates a copy of this record.
23491 * @param {String} id (optional) A new record id if you don't want to use this record's id
23494 copy : function(newId) {
23495 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
23499 * Ext JS Library 1.1.1
23500 * Copyright(c) 2006-2007, Ext JS, LLC.
23502 * Originally Released Under LGPL - original licence link has changed is not relivant.
23505 * <script type="text/javascript">
23511 * @class Roo.data.Store
23512 * @extends Roo.util.Observable
23513 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
23514 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
23516 * 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
23517 * has no knowledge of the format of the data returned by the Proxy.<br>
23519 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
23520 * instances from the data object. These records are cached and made available through accessor functions.
23522 * Creates a new Store.
23523 * @param {Object} config A config object containing the objects needed for the Store to access data,
23524 * and read the data into Records.
23526 Roo.data.Store = function(config){
23527 this.data = new Roo.util.MixedCollection(false);
23528 this.data.getKey = function(o){
23531 this.baseParams = {};
23533 this.paramNames = {
23538 "multisort" : "_multisort"
23541 if(config && config.data){
23542 this.inlineData = config.data;
23543 delete config.data;
23546 Roo.apply(this, config);
23548 if(this.reader){ // reader passed
23549 this.reader = Roo.factory(this.reader, Roo.data);
23550 this.reader.xmodule = this.xmodule || false;
23551 if(!this.recordType){
23552 this.recordType = this.reader.recordType;
23554 if(this.reader.onMetaChange){
23555 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
23559 if(this.recordType){
23560 this.fields = this.recordType.prototype.fields;
23562 this.modified = [];
23566 * @event datachanged
23567 * Fires when the data cache has changed, and a widget which is using this Store
23568 * as a Record cache should refresh its view.
23569 * @param {Store} this
23571 datachanged : true,
23573 * @event metachange
23574 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
23575 * @param {Store} this
23576 * @param {Object} meta The JSON metadata
23581 * Fires when Records have been added to the Store
23582 * @param {Store} this
23583 * @param {Roo.data.Record[]} records The array of Records added
23584 * @param {Number} index The index at which the record(s) were added
23589 * Fires when a Record has been removed from the Store
23590 * @param {Store} this
23591 * @param {Roo.data.Record} record The Record that was removed
23592 * @param {Number} index The index at which the record was removed
23597 * Fires when a Record has been updated
23598 * @param {Store} this
23599 * @param {Roo.data.Record} record The Record that was updated
23600 * @param {String} operation The update operation being performed. Value may be one of:
23602 Roo.data.Record.EDIT
23603 Roo.data.Record.REJECT
23604 Roo.data.Record.COMMIT
23610 * Fires when the data cache has been cleared.
23611 * @param {Store} this
23615 * @event beforeload
23616 * Fires before a request is made for a new data object. If the beforeload handler returns false
23617 * the load action will be canceled.
23618 * @param {Store} this
23619 * @param {Object} options The loading options that were specified (see {@link #load} for details)
23623 * @event beforeloadadd
23624 * Fires after a new set of Records has been loaded.
23625 * @param {Store} this
23626 * @param {Roo.data.Record[]} records The Records that were loaded
23627 * @param {Object} options The loading options that were specified (see {@link #load} for details)
23629 beforeloadadd : true,
23632 * Fires after a new set of Records has been loaded, before they are added to the store.
23633 * @param {Store} this
23634 * @param {Roo.data.Record[]} records The Records that were loaded
23635 * @param {Object} options The loading options that were specified (see {@link #load} for details)
23636 * @params {Object} return from reader
23640 * @event loadexception
23641 * Fires if an exception occurs in the Proxy during loading.
23642 * Called with the signature of the Proxy's "loadexception" event.
23643 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
23646 * @param {Object} return from JsonData.reader() - success, totalRecords, records
23647 * @param {Object} load options
23648 * @param {Object} jsonData from your request (normally this contains the Exception)
23650 loadexception : true
23654 this.proxy = Roo.factory(this.proxy, Roo.data);
23655 this.proxy.xmodule = this.xmodule || false;
23656 this.relayEvents(this.proxy, ["loadexception"]);
23658 this.sortToggle = {};
23659 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
23661 Roo.data.Store.superclass.constructor.call(this);
23663 if(this.inlineData){
23664 this.loadData(this.inlineData);
23665 delete this.inlineData;
23669 Roo.extend(Roo.data.Store, Roo.util.Observable, {
23671 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
23672 * without a remote query - used by combo/forms at present.
23676 * @cfg {Roo.data.DataProxy} proxy [required] The Proxy object which provides access to a data object.
23679 * @cfg {Array} data Inline data to be loaded when the store is initialized.
23682 * @cfg {Roo.data.DataReader} reader [required] The Reader object which processes the data object and returns
23683 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
23686 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
23687 * on any HTTP request
23690 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
23693 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
23697 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
23698 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
23700 remoteSort : false,
23703 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
23704 * loaded or when a record is removed. (defaults to false).
23706 pruneModifiedRecords : false,
23709 lastOptions : null,
23712 * Add Records to the Store and fires the add event.
23713 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
23715 add : function(records){
23716 records = [].concat(records);
23717 for(var i = 0, len = records.length; i < len; i++){
23718 records[i].join(this);
23720 var index = this.data.length;
23721 this.data.addAll(records);
23722 this.fireEvent("add", this, records, index);
23726 * Remove a Record from the Store and fires the remove event.
23727 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
23729 remove : function(record){
23730 var index = this.data.indexOf(record);
23731 this.data.removeAt(index);
23733 if(this.pruneModifiedRecords){
23734 this.modified.remove(record);
23736 this.fireEvent("remove", this, record, index);
23740 * Remove all Records from the Store and fires the clear event.
23742 removeAll : function(){
23744 if(this.pruneModifiedRecords){
23745 this.modified = [];
23747 this.fireEvent("clear", this);
23751 * Inserts Records to the Store at the given index and fires the add event.
23752 * @param {Number} index The start index at which to insert the passed Records.
23753 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
23755 insert : function(index, records){
23756 records = [].concat(records);
23757 for(var i = 0, len = records.length; i < len; i++){
23758 this.data.insert(index, records[i]);
23759 records[i].join(this);
23761 this.fireEvent("add", this, records, index);
23765 * Get the index within the cache of the passed Record.
23766 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
23767 * @return {Number} The index of the passed Record. Returns -1 if not found.
23769 indexOf : function(record){
23770 return this.data.indexOf(record);
23774 * Get the index within the cache of the Record with the passed id.
23775 * @param {String} id The id of the Record to find.
23776 * @return {Number} The index of the Record. Returns -1 if not found.
23778 indexOfId : function(id){
23779 return this.data.indexOfKey(id);
23783 * Get the Record with the specified id.
23784 * @param {String} id The id of the Record to find.
23785 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
23787 getById : function(id){
23788 return this.data.key(id);
23792 * Get the Record at the specified index.
23793 * @param {Number} index The index of the Record to find.
23794 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
23796 getAt : function(index){
23797 return this.data.itemAt(index);
23801 * Returns a range of Records between specified indices.
23802 * @param {Number} startIndex (optional) The starting index (defaults to 0)
23803 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
23804 * @return {Roo.data.Record[]} An array of Records
23806 getRange : function(start, end){
23807 return this.data.getRange(start, end);
23811 storeOptions : function(o){
23812 o = Roo.apply({}, o);
23815 this.lastOptions = o;
23819 * Loads the Record cache from the configured Proxy using the configured Reader.
23821 * If using remote paging, then the first load call must specify the <em>start</em>
23822 * and <em>limit</em> properties in the options.params property to establish the initial
23823 * position within the dataset, and the number of Records to cache on each read from the Proxy.
23825 * <strong>It is important to note that for remote data sources, loading is asynchronous,
23826 * and this call will return before the new data has been loaded. Perform any post-processing
23827 * in a callback function, or in a "load" event handler.</strong>
23829 * @param {Object} options An object containing properties which control loading options:<ul>
23830 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
23831 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
23832 * passed the following arguments:<ul>
23833 * <li>r : Roo.data.Record[]</li>
23834 * <li>options: Options object from the load call</li>
23835 * <li>success: Boolean success indicator</li></ul></li>
23836 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
23837 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
23840 load : function(options){
23841 options = options || {};
23842 if(this.fireEvent("beforeload", this, options) !== false){
23843 this.storeOptions(options);
23844 var p = Roo.apply(options.params || {}, this.baseParams);
23845 // if meta was not loaded from remote source.. try requesting it.
23846 if (!this.reader.metaFromRemote) {
23847 p._requestMeta = 1;
23849 if(this.sortInfo && this.remoteSort){
23850 var pn = this.paramNames;
23851 p[pn["sort"]] = this.sortInfo.field;
23852 p[pn["dir"]] = this.sortInfo.direction;
23854 if (this.multiSort) {
23855 var pn = this.paramNames;
23856 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
23859 this.proxy.load(p, this.reader, this.loadRecords, this, options);
23864 * Reloads the Record cache from the configured Proxy using the configured Reader and
23865 * the options from the last load operation performed.
23866 * @param {Object} options (optional) An object containing properties which may override the options
23867 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
23868 * the most recently used options are reused).
23870 reload : function(options){
23871 this.load(Roo.applyIf(options||{}, this.lastOptions));
23875 // Called as a callback by the Reader during a load operation.
23876 loadRecords : function(o, options, success){
23877 if(!o || success === false){
23878 if(success !== false){
23879 this.fireEvent("load", this, [], options, o);
23881 if(options.callback){
23882 options.callback.call(options.scope || this, [], options, false);
23886 // if data returned failure - throw an exception.
23887 if (o.success === false) {
23888 // show a message if no listener is registered.
23889 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
23890 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
23892 // loadmask wil be hooked into this..
23893 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
23896 var r = o.records, t = o.totalRecords || r.length;
23898 this.fireEvent("beforeloadadd", this, r, options, o);
23900 if(!options || options.add !== true){
23901 if(this.pruneModifiedRecords){
23902 this.modified = [];
23904 for(var i = 0, len = r.length; i < len; i++){
23908 this.data = this.snapshot;
23909 delete this.snapshot;
23912 this.data.addAll(r);
23913 this.totalLength = t;
23915 this.fireEvent("datachanged", this);
23917 this.totalLength = Math.max(t, this.data.length+r.length);
23921 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
23923 var e = new Roo.data.Record({});
23925 e.set(this.parent.displayField, this.parent.emptyTitle);
23926 e.set(this.parent.valueField, '');
23931 this.fireEvent("load", this, r, options, o);
23932 if(options.callback){
23933 options.callback.call(options.scope || this, r, options, true);
23939 * Loads data from a passed data block. A Reader which understands the format of the data
23940 * must have been configured in the constructor.
23941 * @param {Object} data The data block from which to read the Records. The format of the data expected
23942 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
23943 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
23945 loadData : function(o, append){
23946 var r = this.reader.readRecords(o);
23947 this.loadRecords(r, {add: append}, true);
23951 * using 'cn' the nested child reader read the child array into it's child stores.
23952 * @param {Object} rec The record with a 'children array
23954 loadDataFromChildren : function(rec)
23956 this.loadData(this.reader.toLoadData(rec));
23961 * Gets the number of cached records.
23963 * <em>If using paging, this may not be the total size of the dataset. If the data object
23964 * used by the Reader contains the dataset size, then the getTotalCount() function returns
23965 * the data set size</em>
23967 getCount : function(){
23968 return this.data.length || 0;
23972 * Gets the total number of records in the dataset as returned by the server.
23974 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
23975 * the dataset size</em>
23977 getTotalCount : function(){
23978 return this.totalLength || 0;
23982 * Returns the sort state of the Store as an object with two properties:
23984 field {String} The name of the field by which the Records are sorted
23985 direction {String} The sort order, "ASC" or "DESC"
23988 getSortState : function(){
23989 return this.sortInfo;
23993 applySort : function(){
23994 if(this.sortInfo && !this.remoteSort){
23995 var s = this.sortInfo, f = s.field;
23996 var st = this.fields.get(f).sortType;
23997 var fn = function(r1, r2){
23998 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
23999 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
24001 this.data.sort(s.direction, fn);
24002 if(this.snapshot && this.snapshot != this.data){
24003 this.snapshot.sort(s.direction, fn);
24009 * Sets the default sort column and order to be used by the next load operation.
24010 * @param {String} fieldName The name of the field to sort by.
24011 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
24013 setDefaultSort : function(field, dir){
24014 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
24018 * Sort the Records.
24019 * If remote sorting is used, the sort is performed on the server, and the cache is
24020 * reloaded. If local sorting is used, the cache is sorted internally.
24021 * @param {String} fieldName The name of the field to sort by.
24022 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
24024 sort : function(fieldName, dir){
24025 var f = this.fields.get(fieldName);
24027 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
24029 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
24030 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
24035 this.sortToggle[f.name] = dir;
24036 this.sortInfo = {field: f.name, direction: dir};
24037 if(!this.remoteSort){
24039 this.fireEvent("datachanged", this);
24041 this.load(this.lastOptions);
24046 * Calls the specified function for each of the Records in the cache.
24047 * @param {Function} fn The function to call. The Record is passed as the first parameter.
24048 * Returning <em>false</em> aborts and exits the iteration.
24049 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
24051 each : function(fn, scope){
24052 this.data.each(fn, scope);
24056 * Gets all records modified since the last commit. Modified records are persisted across load operations
24057 * (e.g., during paging).
24058 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
24060 getModifiedRecords : function(){
24061 return this.modified;
24065 createFilterFn : function(property, value, anyMatch){
24066 if(!value.exec){ // not a regex
24067 value = String(value);
24068 if(value.length == 0){
24071 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
24073 return function(r){
24074 return value.test(r.data[property]);
24079 * Sums the value of <i>property</i> for each record between start and end and returns the result.
24080 * @param {String} property A field on your records
24081 * @param {Number} start The record index to start at (defaults to 0)
24082 * @param {Number} end The last record index to include (defaults to length - 1)
24083 * @return {Number} The sum
24085 sum : function(property, start, end){
24086 var rs = this.data.items, v = 0;
24087 start = start || 0;
24088 end = (end || end === 0) ? end : rs.length-1;
24090 for(var i = start; i <= end; i++){
24091 v += (rs[i].data[property] || 0);
24097 * Filter the records by a specified property.
24098 * @param {String} field A field on your records
24099 * @param {String/RegExp} value Either a string that the field
24100 * should start with or a RegExp to test against the field
24101 * @param {Boolean} anyMatch True to match any part not just the beginning
24103 filter : function(property, value, anyMatch){
24104 var fn = this.createFilterFn(property, value, anyMatch);
24105 return fn ? this.filterBy(fn) : this.clearFilter();
24109 * Filter by a function. The specified function will be called with each
24110 * record in this data source. If the function returns true the record is included,
24111 * otherwise it is filtered.
24112 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
24113 * @param {Object} scope (optional) The scope of the function (defaults to this)
24115 filterBy : function(fn, scope){
24116 this.snapshot = this.snapshot || this.data;
24117 this.data = this.queryBy(fn, scope||this);
24118 this.fireEvent("datachanged", this);
24122 * Query the records by a specified property.
24123 * @param {String} field A field on your records
24124 * @param {String/RegExp} value Either a string that the field
24125 * should start with or a RegExp to test against the field
24126 * @param {Boolean} anyMatch True to match any part not just the beginning
24127 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
24129 query : function(property, value, anyMatch){
24130 var fn = this.createFilterFn(property, value, anyMatch);
24131 return fn ? this.queryBy(fn) : this.data.clone();
24135 * Query by a function. The specified function will be called with each
24136 * record in this data source. If the function returns true the record is included
24138 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
24139 * @param {Object} scope (optional) The scope of the function (defaults to this)
24140 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
24142 queryBy : function(fn, scope){
24143 var data = this.snapshot || this.data;
24144 return data.filterBy(fn, scope||this);
24148 * Collects unique values for a particular dataIndex from this store.
24149 * @param {String} dataIndex The property to collect
24150 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
24151 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
24152 * @return {Array} An array of the unique values
24154 collect : function(dataIndex, allowNull, bypassFilter){
24155 var d = (bypassFilter === true && this.snapshot) ?
24156 this.snapshot.items : this.data.items;
24157 var v, sv, r = [], l = {};
24158 for(var i = 0, len = d.length; i < len; i++){
24159 v = d[i].data[dataIndex];
24161 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
24170 * Revert to a view of the Record cache with no filtering applied.
24171 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
24173 clearFilter : function(suppressEvent){
24174 if(this.snapshot && this.snapshot != this.data){
24175 this.data = this.snapshot;
24176 delete this.snapshot;
24177 if(suppressEvent !== true){
24178 this.fireEvent("datachanged", this);
24184 afterEdit : function(record){
24185 if(this.modified.indexOf(record) == -1){
24186 this.modified.push(record);
24188 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
24192 afterReject : function(record){
24193 this.modified.remove(record);
24194 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
24198 afterCommit : function(record){
24199 this.modified.remove(record);
24200 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
24204 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
24205 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
24207 commitChanges : function(){
24208 var m = this.modified.slice(0);
24209 this.modified = [];
24210 for(var i = 0, len = m.length; i < len; i++){
24216 * Cancel outstanding changes on all changed records.
24218 rejectChanges : function(){
24219 var m = this.modified.slice(0);
24220 this.modified = [];
24221 for(var i = 0, len = m.length; i < len; i++){
24226 onMetaChange : function(meta, rtype, o){
24227 this.recordType = rtype;
24228 this.fields = rtype.prototype.fields;
24229 delete this.snapshot;
24230 this.sortInfo = meta.sortInfo || this.sortInfo;
24231 this.modified = [];
24232 this.fireEvent('metachange', this, this.reader.meta);
24235 moveIndex : function(data, type)
24237 var index = this.indexOf(data);
24239 var newIndex = index + type;
24243 this.insert(newIndex, data);
24248 * Ext JS Library 1.1.1
24249 * Copyright(c) 2006-2007, Ext JS, LLC.
24251 * Originally Released Under LGPL - original licence link has changed is not relivant.
24254 * <script type="text/javascript">
24258 * @class Roo.data.SimpleStore
24259 * @extends Roo.data.Store
24260 * Small helper class to make creating Stores from Array data easier.
24261 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
24262 * @cfg {Array} fields An array of field definition objects, or field name strings.
24263 * @cfg {Object} an existing reader (eg. copied from another store)
24264 * @cfg {Array} data The multi-dimensional array of data
24265 * @cfg {Roo.data.DataProxy} proxy [not-required]
24266 * @cfg {Roo.data.Reader} reader [not-required]
24268 * @param {Object} config
24270 Roo.data.SimpleStore = function(config)
24272 Roo.data.SimpleStore.superclass.constructor.call(this, {
24274 reader: typeof(config.reader) != 'undefined' ? config.reader : new Roo.data.ArrayReader({
24277 Roo.data.Record.create(config.fields)
24279 proxy : new Roo.data.MemoryProxy(config.data)
24283 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
24285 * Ext JS Library 1.1.1
24286 * Copyright(c) 2006-2007, Ext JS, LLC.
24288 * Originally Released Under LGPL - original licence link has changed is not relivant.
24291 * <script type="text/javascript">
24296 * @extends Roo.data.Store
24297 * @class Roo.data.JsonStore
24298 * Small helper class to make creating Stores for JSON data easier. <br/>
24300 var store = new Roo.data.JsonStore({
24301 url: 'get-images.php',
24303 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
24306 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
24307 * JsonReader and HttpProxy (unless inline data is provided).</b>
24308 * @cfg {Array} fields An array of field definition objects, or field name strings.
24310 * @param {Object} config
24312 Roo.data.JsonStore = function(c){
24313 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
24314 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
24315 reader: new Roo.data.JsonReader(c, c.fields)
24318 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
24320 * Ext JS Library 1.1.1
24321 * Copyright(c) 2006-2007, Ext JS, LLC.
24323 * Originally Released Under LGPL - original licence link has changed is not relivant.
24326 * <script type="text/javascript">
24330 Roo.data.Field = function(config){
24331 if(typeof config == "string"){
24332 config = {name: config};
24334 Roo.apply(this, config);
24337 this.type = "auto";
24340 var st = Roo.data.SortTypes;
24341 // named sortTypes are supported, here we look them up
24342 if(typeof this.sortType == "string"){
24343 this.sortType = st[this.sortType];
24346 // set default sortType for strings and dates
24347 if(!this.sortType){
24350 this.sortType = st.asUCString;
24353 this.sortType = st.asDate;
24356 this.sortType = st.none;
24361 var stripRe = /[\$,%]/g;
24363 // prebuilt conversion function for this field, instead of
24364 // switching every time we're reading a value
24366 var cv, dateFormat = this.dateFormat;
24371 cv = function(v){ return v; };
24374 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
24378 return v !== undefined && v !== null && v !== '' ?
24379 parseInt(String(v).replace(stripRe, ""), 10) : '';
24384 return v !== undefined && v !== null && v !== '' ?
24385 parseFloat(String(v).replace(stripRe, ""), 10) : '';
24390 cv = function(v){ return v === true || v === "true" || v == 1; };
24397 if(v instanceof Date){
24401 if(dateFormat == "timestamp"){
24402 return new Date(v*1000);
24404 return Date.parseDate(v, dateFormat);
24406 var parsed = Date.parse(v);
24407 return parsed ? new Date(parsed) : null;
24416 Roo.data.Field.prototype = {
24424 * Ext JS Library 1.1.1
24425 * Copyright(c) 2006-2007, Ext JS, LLC.
24427 * Originally Released Under LGPL - original licence link has changed is not relivant.
24430 * <script type="text/javascript">
24433 // Base class for reading structured data from a data source. This class is intended to be
24434 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
24437 * @class Roo.data.DataReader
24439 * Base class for reading structured data from a data source. This class is intended to be
24440 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
24443 Roo.data.DataReader = function(meta, recordType){
24447 this.recordType = recordType instanceof Array ?
24448 Roo.data.Record.create(recordType) : recordType;
24451 Roo.data.DataReader.prototype = {
24454 readerType : 'Data',
24456 * Create an empty record
24457 * @param {Object} data (optional) - overlay some values
24458 * @return {Roo.data.Record} record created.
24460 newRow : function(d) {
24462 this.recordType.prototype.fields.each(function(c) {
24464 case 'int' : da[c.name] = 0; break;
24465 case 'date' : da[c.name] = new Date(); break;
24466 case 'float' : da[c.name] = 0.0; break;
24467 case 'boolean' : da[c.name] = false; break;
24468 default : da[c.name] = ""; break;
24472 return new this.recordType(Roo.apply(da, d));
24478 * Ext JS Library 1.1.1
24479 * Copyright(c) 2006-2007, Ext JS, LLC.
24481 * Originally Released Under LGPL - original licence link has changed is not relivant.
24484 * <script type="text/javascript">
24488 * @class Roo.data.DataProxy
24489 * @extends Roo.data.Observable
24491 * This class is an abstract base class for implementations which provide retrieval of
24492 * unformatted data objects.<br>
24494 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
24495 * (of the appropriate type which knows how to parse the data object) to provide a block of
24496 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
24498 * Custom implementations must implement the load method as described in
24499 * {@link Roo.data.HttpProxy#load}.
24501 Roo.data.DataProxy = function(){
24504 * @event beforeload
24505 * Fires before a network request is made to retrieve a data object.
24506 * @param {Object} This DataProxy object.
24507 * @param {Object} params The params parameter to the load function.
24512 * Fires before the load method's callback is called.
24513 * @param {Object} This DataProxy object.
24514 * @param {Object} o The data object.
24515 * @param {Object} arg The callback argument object passed to the load function.
24519 * @event loadexception
24520 * Fires if an Exception occurs during data retrieval.
24521 * @param {Object} This DataProxy object.
24522 * @param {Object} o The data object.
24523 * @param {Object} arg The callback argument object passed to the load function.
24524 * @param {Object} e The Exception.
24526 loadexception : true
24528 Roo.data.DataProxy.superclass.constructor.call(this);
24531 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
24534 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
24538 * Ext JS Library 1.1.1
24539 * Copyright(c) 2006-2007, Ext JS, LLC.
24541 * Originally Released Under LGPL - original licence link has changed is not relivant.
24544 * <script type="text/javascript">
24547 * @class Roo.data.MemoryProxy
24548 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
24549 * to the Reader when its load method is called.
24551 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
24553 Roo.data.MemoryProxy = function(data){
24557 Roo.data.MemoryProxy.superclass.constructor.call(this);
24561 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
24564 * Load data from the requested source (in this case an in-memory
24565 * data object passed to the constructor), read the data object into
24566 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
24567 * process that block using the passed callback.
24568 * @param {Object} params This parameter is not used by the MemoryProxy class.
24569 * @param {Roo.data.DataReader} reader The Reader object which converts the data
24570 * object into a block of Roo.data.Records.
24571 * @param {Function} callback The function into which to pass the block of Roo.data.records.
24572 * The function must be passed <ul>
24573 * <li>The Record block object</li>
24574 * <li>The "arg" argument from the load function</li>
24575 * <li>A boolean success indicator</li>
24577 * @param {Object} scope The scope in which to call the callback
24578 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
24580 load : function(params, reader, callback, scope, arg){
24581 params = params || {};
24584 result = reader.readRecords(params.data ? params.data :this.data);
24586 this.fireEvent("loadexception", this, arg, null, e);
24587 callback.call(scope, null, arg, false);
24590 callback.call(scope, result, arg, true);
24594 update : function(params, records){
24599 * Ext JS Library 1.1.1
24600 * Copyright(c) 2006-2007, Ext JS, LLC.
24602 * Originally Released Under LGPL - original licence link has changed is not relivant.
24605 * <script type="text/javascript">
24608 * @class Roo.data.HttpProxy
24609 * @extends Roo.data.DataProxy
24610 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
24611 * configured to reference a certain URL.<br><br>
24613 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
24614 * from which the running page was served.<br><br>
24616 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
24618 * Be aware that to enable the browser to parse an XML document, the server must set
24619 * the Content-Type header in the HTTP response to "text/xml".
24621 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
24622 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
24623 * will be used to make the request.
24625 Roo.data.HttpProxy = function(conn){
24626 Roo.data.HttpProxy.superclass.constructor.call(this);
24627 // is conn a conn config or a real conn?
24629 this.useAjax = !conn || !conn.events;
24633 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
24634 // thse are take from connection...
24637 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
24640 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
24641 * extra parameters to each request made by this object. (defaults to undefined)
24644 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
24645 * to each request made by this object. (defaults to undefined)
24648 * @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)
24651 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
24654 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
24660 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
24664 * Return the {@link Roo.data.Connection} object being used by this Proxy.
24665 * @return {Connection} The Connection object. This object may be used to subscribe to events on
24666 * a finer-grained basis than the DataProxy events.
24668 getConnection : function(){
24669 return this.useAjax ? Roo.Ajax : this.conn;
24673 * Load data from the configured {@link Roo.data.Connection}, read the data object into
24674 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
24675 * process that block using the passed callback.
24676 * @param {Object} params An object containing properties which are to be used as HTTP parameters
24677 * for the request to the remote server.
24678 * @param {Roo.data.DataReader} reader The Reader object which converts the data
24679 * object into a block of Roo.data.Records.
24680 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
24681 * The function must be passed <ul>
24682 * <li>The Record block object</li>
24683 * <li>The "arg" argument from the load function</li>
24684 * <li>A boolean success indicator</li>
24686 * @param {Object} scope The scope in which to call the callback
24687 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
24689 load : function(params, reader, callback, scope, arg){
24690 if(this.fireEvent("beforeload", this, params) !== false){
24692 params : params || {},
24694 callback : callback,
24699 callback : this.loadResponse,
24703 Roo.applyIf(o, this.conn);
24704 if(this.activeRequest){
24705 Roo.Ajax.abort(this.activeRequest);
24707 this.activeRequest = Roo.Ajax.request(o);
24709 this.conn.request(o);
24712 callback.call(scope||this, null, arg, false);
24717 loadResponse : function(o, success, response){
24718 delete this.activeRequest;
24720 this.fireEvent("loadexception", this, o, response);
24721 o.request.callback.call(o.request.scope, null, o.request.arg, false);
24726 result = o.reader.read(response);
24728 this.fireEvent("loadexception", this, o, response, e);
24729 o.request.callback.call(o.request.scope, null, o.request.arg, false);
24733 this.fireEvent("load", this, o, o.request.arg);
24734 o.request.callback.call(o.request.scope, result, o.request.arg, true);
24738 update : function(dataSet){
24743 updateResponse : function(dataSet){
24748 * Ext JS Library 1.1.1
24749 * Copyright(c) 2006-2007, Ext JS, LLC.
24751 * Originally Released Under LGPL - original licence link has changed is not relivant.
24754 * <script type="text/javascript">
24758 * @class Roo.data.ScriptTagProxy
24759 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
24760 * other than the originating domain of the running page.<br><br>
24762 * <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
24763 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
24765 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
24766 * source code that is used as the source inside a <script> tag.<br><br>
24768 * In order for the browser to process the returned data, the server must wrap the data object
24769 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
24770 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
24771 * depending on whether the callback name was passed:
24774 boolean scriptTag = false;
24775 String cb = request.getParameter("callback");
24778 response.setContentType("text/javascript");
24780 response.setContentType("application/x-json");
24782 Writer out = response.getWriter();
24784 out.write(cb + "(");
24786 out.print(dataBlock.toJsonString());
24793 * @param {Object} config A configuration object.
24795 Roo.data.ScriptTagProxy = function(config){
24796 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
24797 Roo.apply(this, config);
24798 this.head = document.getElementsByTagName("head")[0];
24801 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
24803 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
24805 * @cfg {String} url The URL from which to request the data object.
24808 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
24812 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
24813 * the server the name of the callback function set up by the load call to process the returned data object.
24814 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
24815 * javascript output which calls this named function passing the data object as its only parameter.
24817 callbackParam : "callback",
24819 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
24820 * name to the request.
24825 * Load data from the configured URL, read the data object into
24826 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
24827 * process that block using the passed callback.
24828 * @param {Object} params An object containing properties which are to be used as HTTP parameters
24829 * for the request to the remote server.
24830 * @param {Roo.data.DataReader} reader The Reader object which converts the data
24831 * object into a block of Roo.data.Records.
24832 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
24833 * The function must be passed <ul>
24834 * <li>The Record block object</li>
24835 * <li>The "arg" argument from the load function</li>
24836 * <li>A boolean success indicator</li>
24838 * @param {Object} scope The scope in which to call the callback
24839 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
24841 load : function(params, reader, callback, scope, arg){
24842 if(this.fireEvent("beforeload", this, params) !== false){
24844 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
24846 var url = this.url;
24847 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
24849 url += "&_dc=" + (new Date().getTime());
24851 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
24854 cb : "stcCallback"+transId,
24855 scriptId : "stcScript"+transId,
24859 callback : callback,
24865 window[trans.cb] = function(o){
24866 conn.handleResponse(o, trans);
24869 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
24871 if(this.autoAbort !== false){
24875 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
24877 var script = document.createElement("script");
24878 script.setAttribute("src", url);
24879 script.setAttribute("type", "text/javascript");
24880 script.setAttribute("id", trans.scriptId);
24881 this.head.appendChild(script);
24883 this.trans = trans;
24885 callback.call(scope||this, null, arg, false);
24890 isLoading : function(){
24891 return this.trans ? true : false;
24895 * Abort the current server request.
24897 abort : function(){
24898 if(this.isLoading()){
24899 this.destroyTrans(this.trans);
24904 destroyTrans : function(trans, isLoaded){
24905 this.head.removeChild(document.getElementById(trans.scriptId));
24906 clearTimeout(trans.timeoutId);
24908 window[trans.cb] = undefined;
24910 delete window[trans.cb];
24913 // if hasn't been loaded, wait for load to remove it to prevent script error
24914 window[trans.cb] = function(){
24915 window[trans.cb] = undefined;
24917 delete window[trans.cb];
24924 handleResponse : function(o, trans){
24925 this.trans = false;
24926 this.destroyTrans(trans, true);
24929 result = trans.reader.readRecords(o);
24931 this.fireEvent("loadexception", this, o, trans.arg, e);
24932 trans.callback.call(trans.scope||window, null, trans.arg, false);
24935 this.fireEvent("load", this, o, trans.arg);
24936 trans.callback.call(trans.scope||window, result, trans.arg, true);
24940 handleFailure : function(trans){
24941 this.trans = false;
24942 this.destroyTrans(trans, false);
24943 this.fireEvent("loadexception", this, null, trans.arg);
24944 trans.callback.call(trans.scope||window, null, trans.arg, false);
24948 * Ext JS Library 1.1.1
24949 * Copyright(c) 2006-2007, Ext JS, LLC.
24951 * Originally Released Under LGPL - original licence link has changed is not relivant.
24954 * <script type="text/javascript">
24958 * @class Roo.data.JsonReader
24959 * @extends Roo.data.DataReader
24960 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
24961 * based on mappings in a provided Roo.data.Record constructor.
24963 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
24964 * in the reply previously.
24969 var RecordDef = Roo.data.Record.create([
24970 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
24971 {name: 'occupation'} // This field will use "occupation" as the mapping.
24973 var myReader = new Roo.data.JsonReader({
24974 totalProperty: "results", // The property which contains the total dataset size (optional)
24975 root: "rows", // The property which contains an Array of row objects
24976 id: "id" // The property within each row object that provides an ID for the record (optional)
24980 * This would consume a JSON file like this:
24982 { 'results': 2, 'rows': [
24983 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
24984 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
24987 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
24988 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
24989 * paged from the remote server.
24990 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
24991 * @cfg {String} root name of the property which contains the Array of row objects.
24992 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
24993 * @cfg {Array} fields Array of field definition objects
24995 * Create a new JsonReader
24996 * @param {Object} meta Metadata configuration options
24997 * @param {Object} recordType Either an Array of field definition objects,
24998 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
25000 Roo.data.JsonReader = function(meta, recordType){
25003 // set some defaults:
25004 Roo.applyIf(meta, {
25005 totalProperty: 'total',
25006 successProperty : 'success',
25011 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
25013 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
25015 readerType : 'Json',
25018 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
25019 * Used by Store query builder to append _requestMeta to params.
25022 metaFromRemote : false,
25024 * This method is only used by a DataProxy which has retrieved data from a remote server.
25025 * @param {Object} response The XHR object which contains the JSON data in its responseText.
25026 * @return {Object} data A data block which is used by an Roo.data.Store object as
25027 * a cache of Roo.data.Records.
25029 read : function(response){
25030 var json = response.responseText;
25032 var o = /* eval:var:o */ eval("("+json+")");
25034 throw {message: "JsonReader.read: Json object not found"};
25040 this.metaFromRemote = true;
25041 this.meta = o.metaData;
25042 this.recordType = Roo.data.Record.create(o.metaData.fields);
25043 this.onMetaChange(this.meta, this.recordType, o);
25045 return this.readRecords(o);
25048 // private function a store will implement
25049 onMetaChange : function(meta, recordType, o){
25056 simpleAccess: function(obj, subsc) {
25063 getJsonAccessor: function(){
25065 return function(expr) {
25067 return(re.test(expr))
25068 ? new Function("obj", "return obj." + expr)
25073 return Roo.emptyFn;
25078 * Create a data block containing Roo.data.Records from an XML document.
25079 * @param {Object} o An object which contains an Array of row objects in the property specified
25080 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
25081 * which contains the total size of the dataset.
25082 * @return {Object} data A data block which is used by an Roo.data.Store object as
25083 * a cache of Roo.data.Records.
25085 readRecords : function(o){
25087 * After any data loads, the raw JSON data is available for further custom processing.
25091 var s = this.meta, Record = this.recordType,
25092 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
25094 // Generate extraction functions for the totalProperty, the root, the id, and for each field
25096 if(s.totalProperty) {
25097 this.getTotal = this.getJsonAccessor(s.totalProperty);
25099 if(s.successProperty) {
25100 this.getSuccess = this.getJsonAccessor(s.successProperty);
25102 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
25104 var g = this.getJsonAccessor(s.id);
25105 this.getId = function(rec) {
25107 return (r === undefined || r === "") ? null : r;
25110 this.getId = function(){return null;};
25113 for(var jj = 0; jj < fl; jj++){
25115 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
25116 this.ef[jj] = this.getJsonAccessor(map);
25120 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
25121 if(s.totalProperty){
25122 var vt = parseInt(this.getTotal(o), 10);
25127 if(s.successProperty){
25128 var vs = this.getSuccess(o);
25129 if(vs === false || vs === 'false'){
25134 for(var i = 0; i < c; i++){
25137 var id = this.getId(n);
25138 for(var j = 0; j < fl; j++){
25140 var v = this.ef[j](n);
25142 Roo.log('missing convert for ' + f.name);
25146 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
25148 var record = new Record(values, id);
25150 records[i] = record;
25156 totalRecords : totalRecords
25159 // used when loading children.. @see loadDataFromChildren
25160 toLoadData: function(rec)
25162 // expect rec just to be an array.. eg [a,b,c, [...] << cn ]
25163 var data = typeof(rec.data.cn) == 'undefined' ? [] : rec.data.cn;
25164 return { data : data, total : data.length };
25169 * Ext JS Library 1.1.1
25170 * Copyright(c) 2006-2007, Ext JS, LLC.
25172 * Originally Released Under LGPL - original licence link has changed is not relivant.
25175 * <script type="text/javascript">
25179 * @class Roo.data.XmlReader
25180 * @extends Roo.data.DataReader
25181 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
25182 * based on mappings in a provided Roo.data.Record constructor.<br><br>
25184 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
25185 * header in the HTTP response must be set to "text/xml".</em>
25189 var RecordDef = Roo.data.Record.create([
25190 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
25191 {name: 'occupation'} // This field will use "occupation" as the mapping.
25193 var myReader = new Roo.data.XmlReader({
25194 totalRecords: "results", // The element which contains the total dataset size (optional)
25195 record: "row", // The repeated element which contains row information
25196 id: "id" // The element within the row that provides an ID for the record (optional)
25200 * This would consume an XML file like this:
25204 <results>2</results>
25207 <name>Bill</name>
25208 <occupation>Gardener</occupation>
25212 <name>Ben</name>
25213 <occupation>Horticulturalist</occupation>
25217 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
25218 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
25219 * paged from the remote server.
25220 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
25221 * @cfg {String} success The DomQuery path to the success attribute used by forms.
25222 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
25223 * a record identifier value.
25225 * Create a new XmlReader
25226 * @param {Object} meta Metadata configuration options
25227 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
25228 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
25229 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
25231 Roo.data.XmlReader = function(meta, recordType){
25233 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
25235 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
25237 readerType : 'Xml',
25240 * This method is only used by a DataProxy which has retrieved data from a remote server.
25241 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
25242 * to contain a method called 'responseXML' that returns an XML document object.
25243 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
25244 * a cache of Roo.data.Records.
25246 read : function(response){
25247 var doc = response.responseXML;
25249 throw {message: "XmlReader.read: XML Document not available"};
25251 return this.readRecords(doc);
25255 * Create a data block containing Roo.data.Records from an XML document.
25256 * @param {Object} doc A parsed XML document.
25257 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
25258 * a cache of Roo.data.Records.
25260 readRecords : function(doc){
25262 * After any data loads/reads, the raw XML Document is available for further custom processing.
25263 * @type XMLDocument
25265 this.xmlData = doc;
25266 var root = doc.documentElement || doc;
25267 var q = Roo.DomQuery;
25268 var recordType = this.recordType, fields = recordType.prototype.fields;
25269 var sid = this.meta.id;
25270 var totalRecords = 0, success = true;
25271 if(this.meta.totalRecords){
25272 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
25275 if(this.meta.success){
25276 var sv = q.selectValue(this.meta.success, root, true);
25277 success = sv !== false && sv !== 'false';
25280 var ns = q.select(this.meta.record, root);
25281 for(var i = 0, len = ns.length; i < len; i++) {
25284 var id = sid ? q.selectValue(sid, n) : undefined;
25285 for(var j = 0, jlen = fields.length; j < jlen; j++){
25286 var f = fields.items[j];
25287 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
25289 values[f.name] = v;
25291 var record = new recordType(values, id);
25293 records[records.length] = record;
25299 totalRecords : totalRecords || records.length
25304 * Ext JS Library 1.1.1
25305 * Copyright(c) 2006-2007, Ext JS, LLC.
25307 * Originally Released Under LGPL - original licence link has changed is not relivant.
25310 * <script type="text/javascript">
25314 * @class Roo.data.ArrayReader
25315 * @extends Roo.data.DataReader
25316 * Data reader class to create an Array of Roo.data.Record objects from an Array.
25317 * Each element of that Array represents a row of data fields. The
25318 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
25319 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
25323 var RecordDef = Roo.data.Record.create([
25324 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
25325 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
25327 var myReader = new Roo.data.ArrayReader({
25328 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
25332 * This would consume an Array like this:
25334 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
25338 * Create a new JsonReader
25339 * @param {Object} meta Metadata configuration options.
25340 * @param {Object|Array} recordType Either an Array of field definition objects
25342 * @cfg {Array} fields Array of field definition objects
25343 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
25344 * as specified to {@link Roo.data.Record#create},
25345 * or an {@link Roo.data.Record} object
25348 * created using {@link Roo.data.Record#create}.
25350 Roo.data.ArrayReader = function(meta, recordType)
25352 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType||meta.fields);
25355 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
25358 * Create a data block containing Roo.data.Records from an XML document.
25359 * @param {Object} o An Array of row objects which represents the dataset.
25360 * @return {Object} A data block which is used by an {@link Roo.data.Store} object as
25361 * a cache of Roo.data.Records.
25363 readRecords : function(o)
25365 var sid = this.meta ? this.meta.id : null;
25366 var recordType = this.recordType, fields = recordType.prototype.fields;
25369 for(var i = 0; i < root.length; i++){
25372 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
25373 for(var j = 0, jlen = fields.length; j < jlen; j++){
25374 var f = fields.items[j];
25375 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
25376 var v = n[k] !== undefined ? n[k] : f.defaultValue;
25378 values[f.name] = v;
25380 var record = new recordType(values, id);
25382 records[records.length] = record;
25386 totalRecords : records.length
25389 // used when loading children.. @see loadDataFromChildren
25390 toLoadData: function(rec)
25392 // expect rec just to be an array.. eg [a,b,c, [...] << cn ]
25393 return typeof(rec.data.cn) == 'undefined' ? [] : rec.data.cn;
25400 * Ext JS Library 1.1.1
25401 * Copyright(c) 2006-2007, Ext JS, LLC.
25403 * Originally Released Under LGPL - original licence link has changed is not relivant.
25406 * <script type="text/javascript">
25411 * @class Roo.data.Tree
25412 * @extends Roo.util.Observable
25413 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
25414 * in the tree have most standard DOM functionality.
25416 * @param {Node} root (optional) The root node
25418 Roo.data.Tree = function(root){
25419 this.nodeHash = {};
25421 * The root node for this tree
25426 this.setRootNode(root);
25431 * Fires when a new child node is appended to a node in this tree.
25432 * @param {Tree} tree The owner tree
25433 * @param {Node} parent The parent node
25434 * @param {Node} node The newly appended node
25435 * @param {Number} index The index of the newly appended node
25440 * Fires when a child node is removed from a node in this tree.
25441 * @param {Tree} tree The owner tree
25442 * @param {Node} parent The parent node
25443 * @param {Node} node The child node removed
25448 * Fires when a node is moved to a new location in the tree
25449 * @param {Tree} tree The owner tree
25450 * @param {Node} node The node moved
25451 * @param {Node} oldParent The old parent of this node
25452 * @param {Node} newParent The new parent of this node
25453 * @param {Number} index The index it was moved to
25458 * Fires when a new child node is inserted in a node in this tree.
25459 * @param {Tree} tree The owner tree
25460 * @param {Node} parent The parent node
25461 * @param {Node} node The child node inserted
25462 * @param {Node} refNode The child node the node was inserted before
25466 * @event beforeappend
25467 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
25468 * @param {Tree} tree The owner tree
25469 * @param {Node} parent The parent node
25470 * @param {Node} node The child node to be appended
25472 "beforeappend" : true,
25474 * @event beforeremove
25475 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
25476 * @param {Tree} tree The owner tree
25477 * @param {Node} parent The parent node
25478 * @param {Node} node The child node to be removed
25480 "beforeremove" : true,
25482 * @event beforemove
25483 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
25484 * @param {Tree} tree The owner tree
25485 * @param {Node} node The node being moved
25486 * @param {Node} oldParent The parent of the node
25487 * @param {Node} newParent The new parent the node is moving to
25488 * @param {Number} index The index it is being moved to
25490 "beforemove" : true,
25492 * @event beforeinsert
25493 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
25494 * @param {Tree} tree The owner tree
25495 * @param {Node} parent The parent node
25496 * @param {Node} node The child node to be inserted
25497 * @param {Node} refNode The child node the node is being inserted before
25499 "beforeinsert" : true
25502 Roo.data.Tree.superclass.constructor.call(this);
25505 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
25506 pathSeparator: "/",
25508 proxyNodeEvent : function(){
25509 return this.fireEvent.apply(this, arguments);
25513 * Returns the root node for this tree.
25516 getRootNode : function(){
25521 * Sets the root node for this tree.
25522 * @param {Node} node
25525 setRootNode : function(node){
25527 node.ownerTree = this;
25528 node.isRoot = true;
25529 this.registerNode(node);
25534 * Gets a node in this tree by its id.
25535 * @param {String} id
25538 getNodeById : function(id){
25539 return this.nodeHash[id];
25542 registerNode : function(node){
25543 this.nodeHash[node.id] = node;
25546 unregisterNode : function(node){
25547 delete this.nodeHash[node.id];
25550 toString : function(){
25551 return "[Tree"+(this.id?" "+this.id:"")+"]";
25556 * @class Roo.data.Node
25557 * @extends Roo.util.Observable
25558 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
25559 * @cfg {String} id The id for this node. If one is not specified, one is generated.
25561 * @param {Object} attributes The attributes/config for the node
25563 Roo.data.Node = function(attributes){
25565 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
25568 this.attributes = attributes || {};
25569 this.leaf = this.attributes.leaf;
25571 * The node id. @type String
25573 this.id = this.attributes.id;
25575 this.id = Roo.id(null, "ynode-");
25576 this.attributes.id = this.id;
25581 * All child nodes of this node. @type Array
25583 this.childNodes = [];
25584 if(!this.childNodes.indexOf){ // indexOf is a must
25585 this.childNodes.indexOf = function(o){
25586 for(var i = 0, len = this.length; i < len; i++){
25595 * The parent node for this node. @type Node
25597 this.parentNode = null;
25599 * The first direct child node of this node, or null if this node has no child nodes. @type Node
25601 this.firstChild = null;
25603 * The last direct child node of this node, or null if this node has no child nodes. @type Node
25605 this.lastChild = null;
25607 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
25609 this.previousSibling = null;
25611 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
25613 this.nextSibling = null;
25618 * Fires when a new child node is appended
25619 * @param {Tree} tree The owner tree
25620 * @param {Node} this This node
25621 * @param {Node} node The newly appended node
25622 * @param {Number} index The index of the newly appended node
25627 * Fires when a child node is removed
25628 * @param {Tree} tree The owner tree
25629 * @param {Node} this This node
25630 * @param {Node} node The removed node
25635 * Fires when this node is moved to a new location in the tree
25636 * @param {Tree} tree The owner tree
25637 * @param {Node} this This node
25638 * @param {Node} oldParent The old parent of this node
25639 * @param {Node} newParent The new parent of this node
25640 * @param {Number} index The index it was moved to
25645 * Fires when a new child node is inserted.
25646 * @param {Tree} tree The owner tree
25647 * @param {Node} this This node
25648 * @param {Node} node The child node inserted
25649 * @param {Node} refNode The child node the node was inserted before
25653 * @event beforeappend
25654 * Fires before a new child is appended, return false to cancel the append.
25655 * @param {Tree} tree The owner tree
25656 * @param {Node} this This node
25657 * @param {Node} node The child node to be appended
25659 "beforeappend" : true,
25661 * @event beforeremove
25662 * Fires before a child is removed, return false to cancel the remove.
25663 * @param {Tree} tree The owner tree
25664 * @param {Node} this This node
25665 * @param {Node} node The child node to be removed
25667 "beforeremove" : true,
25669 * @event beforemove
25670 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
25671 * @param {Tree} tree The owner tree
25672 * @param {Node} this This node
25673 * @param {Node} oldParent The parent of this node
25674 * @param {Node} newParent The new parent this node is moving to
25675 * @param {Number} index The index it is being moved to
25677 "beforemove" : true,
25679 * @event beforeinsert
25680 * Fires before a new child is inserted, return false to cancel the insert.
25681 * @param {Tree} tree The owner tree
25682 * @param {Node} this This node
25683 * @param {Node} node The child node to be inserted
25684 * @param {Node} refNode The child node the node is being inserted before
25686 "beforeinsert" : true
25688 this.listeners = this.attributes.listeners;
25689 Roo.data.Node.superclass.constructor.call(this);
25692 Roo.extend(Roo.data.Node, Roo.util.Observable, {
25693 fireEvent : function(evtName){
25694 // first do standard event for this node
25695 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
25698 // then bubble it up to the tree if the event wasn't cancelled
25699 var ot = this.getOwnerTree();
25701 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
25709 * Returns true if this node is a leaf
25710 * @return {Boolean}
25712 isLeaf : function(){
25713 return this.leaf === true;
25717 setFirstChild : function(node){
25718 this.firstChild = node;
25722 setLastChild : function(node){
25723 this.lastChild = node;
25728 * Returns true if this node is the last child of its parent
25729 * @return {Boolean}
25731 isLast : function(){
25732 return (!this.parentNode ? true : this.parentNode.lastChild == this);
25736 * Returns true if this node is the first child of its parent
25737 * @return {Boolean}
25739 isFirst : function(){
25740 return (!this.parentNode ? true : this.parentNode.firstChild == this);
25743 hasChildNodes : function(){
25744 return !this.isLeaf() && this.childNodes.length > 0;
25748 * Insert node(s) as the last child node of this node.
25749 * @param {Node/Array} node The node or Array of nodes to append
25750 * @return {Node} The appended node if single append, or null if an array was passed
25752 appendChild : function(node){
25754 if(node instanceof Array){
25756 }else if(arguments.length > 1){
25760 // if passed an array or multiple args do them one by one
25762 for(var i = 0, len = multi.length; i < len; i++) {
25763 this.appendChild(multi[i]);
25766 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
25769 var index = this.childNodes.length;
25770 var oldParent = node.parentNode;
25771 // it's a move, make sure we move it cleanly
25773 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
25776 oldParent.removeChild(node);
25779 index = this.childNodes.length;
25781 this.setFirstChild(node);
25783 this.childNodes.push(node);
25784 node.parentNode = this;
25785 var ps = this.childNodes[index-1];
25787 node.previousSibling = ps;
25788 ps.nextSibling = node;
25790 node.previousSibling = null;
25792 node.nextSibling = null;
25793 this.setLastChild(node);
25794 node.setOwnerTree(this.getOwnerTree());
25795 this.fireEvent("append", this.ownerTree, this, node, index);
25796 if(this.ownerTree) {
25797 this.ownerTree.fireEvent("appendnode", this, node, index);
25800 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
25807 * Removes a child node from this node.
25808 * @param {Node} node The node to remove
25809 * @return {Node} The removed node
25811 removeChild : function(node){
25812 var index = this.childNodes.indexOf(node);
25816 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
25820 // remove it from childNodes collection
25821 this.childNodes.splice(index, 1);
25824 if(node.previousSibling){
25825 node.previousSibling.nextSibling = node.nextSibling;
25827 if(node.nextSibling){
25828 node.nextSibling.previousSibling = node.previousSibling;
25831 // update child refs
25832 if(this.firstChild == node){
25833 this.setFirstChild(node.nextSibling);
25835 if(this.lastChild == node){
25836 this.setLastChild(node.previousSibling);
25839 node.setOwnerTree(null);
25840 // clear any references from the node
25841 node.parentNode = null;
25842 node.previousSibling = null;
25843 node.nextSibling = null;
25844 this.fireEvent("remove", this.ownerTree, this, node);
25849 * Inserts the first node before the second node in this nodes childNodes collection.
25850 * @param {Node} node The node to insert
25851 * @param {Node} refNode The node to insert before (if null the node is appended)
25852 * @return {Node} The inserted node
25854 insertBefore : function(node, refNode){
25855 if(!refNode){ // like standard Dom, refNode can be null for append
25856 return this.appendChild(node);
25859 if(node == refNode){
25863 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
25866 var index = this.childNodes.indexOf(refNode);
25867 var oldParent = node.parentNode;
25868 var refIndex = index;
25870 // when moving internally, indexes will change after remove
25871 if(oldParent == this && this.childNodes.indexOf(node) < index){
25875 // it's a move, make sure we move it cleanly
25877 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
25880 oldParent.removeChild(node);
25883 this.setFirstChild(node);
25885 this.childNodes.splice(refIndex, 0, node);
25886 node.parentNode = this;
25887 var ps = this.childNodes[refIndex-1];
25889 node.previousSibling = ps;
25890 ps.nextSibling = node;
25892 node.previousSibling = null;
25894 node.nextSibling = refNode;
25895 refNode.previousSibling = node;
25896 node.setOwnerTree(this.getOwnerTree());
25897 this.fireEvent("insert", this.ownerTree, this, node, refNode);
25899 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
25905 * Returns the child node at the specified index.
25906 * @param {Number} index
25909 item : function(index){
25910 return this.childNodes[index];
25914 * Replaces one child node in this node with another.
25915 * @param {Node} newChild The replacement node
25916 * @param {Node} oldChild The node to replace
25917 * @return {Node} The replaced node
25919 replaceChild : function(newChild, oldChild){
25920 this.insertBefore(newChild, oldChild);
25921 this.removeChild(oldChild);
25926 * Returns the index of a child node
25927 * @param {Node} node
25928 * @return {Number} The index of the node or -1 if it was not found
25930 indexOf : function(child){
25931 return this.childNodes.indexOf(child);
25935 * Returns the tree this node is in.
25938 getOwnerTree : function(){
25939 // if it doesn't have one, look for one
25940 if(!this.ownerTree){
25944 this.ownerTree = p.ownerTree;
25950 return this.ownerTree;
25954 * Returns depth of this node (the root node has a depth of 0)
25957 getDepth : function(){
25960 while(p.parentNode){
25968 setOwnerTree : function(tree){
25969 // if it's move, we need to update everyone
25970 if(tree != this.ownerTree){
25971 if(this.ownerTree){
25972 this.ownerTree.unregisterNode(this);
25974 this.ownerTree = tree;
25975 var cs = this.childNodes;
25976 for(var i = 0, len = cs.length; i < len; i++) {
25977 cs[i].setOwnerTree(tree);
25980 tree.registerNode(this);
25986 * Returns the path for this node. The path can be used to expand or select this node programmatically.
25987 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
25988 * @return {String} The path
25990 getPath : function(attr){
25991 attr = attr || "id";
25992 var p = this.parentNode;
25993 var b = [this.attributes[attr]];
25995 b.unshift(p.attributes[attr]);
25998 var sep = this.getOwnerTree().pathSeparator;
25999 return sep + b.join(sep);
26003 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
26004 * function call will be the scope provided or the current node. The arguments to the function
26005 * will be the args provided or the current node. If the function returns false at any point,
26006 * the bubble is stopped.
26007 * @param {Function} fn The function to call
26008 * @param {Object} scope (optional) The scope of the function (defaults to current node)
26009 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
26011 bubble : function(fn, scope, args){
26014 if(fn.call(scope || p, args || p) === false){
26022 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
26023 * function call will be the scope provided or the current node. The arguments to the function
26024 * will be the args provided or the current node. If the function returns false at any point,
26025 * the cascade is stopped on that branch.
26026 * @param {Function} fn The function to call
26027 * @param {Object} scope (optional) The scope of the function (defaults to current node)
26028 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
26030 cascade : function(fn, scope, args){
26031 if(fn.call(scope || this, args || this) !== false){
26032 var cs = this.childNodes;
26033 for(var i = 0, len = cs.length; i < len; i++) {
26034 cs[i].cascade(fn, scope, args);
26040 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
26041 * function call will be the scope provided or the current node. The arguments to the function
26042 * will be the args provided or the current node. If the function returns false at any point,
26043 * the iteration stops.
26044 * @param {Function} fn The function to call
26045 * @param {Object} scope (optional) The scope of the function (defaults to current node)
26046 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
26048 eachChild : function(fn, scope, args){
26049 var cs = this.childNodes;
26050 for(var i = 0, len = cs.length; i < len; i++) {
26051 if(fn.call(scope || this, args || cs[i]) === false){
26058 * Finds the first child that has the attribute with the specified value.
26059 * @param {String} attribute The attribute name
26060 * @param {Mixed} value The value to search for
26061 * @return {Node} The found child or null if none was found
26063 findChild : function(attribute, value){
26064 var cs = this.childNodes;
26065 for(var i = 0, len = cs.length; i < len; i++) {
26066 if(cs[i].attributes[attribute] == value){
26074 * Finds the first child by a custom function. The child matches if the function passed
26076 * @param {Function} fn
26077 * @param {Object} scope (optional)
26078 * @return {Node} The found child or null if none was found
26080 findChildBy : function(fn, scope){
26081 var cs = this.childNodes;
26082 for(var i = 0, len = cs.length; i < len; i++) {
26083 if(fn.call(scope||cs[i], cs[i]) === true){
26091 * Sorts this nodes children using the supplied sort function
26092 * @param {Function} fn
26093 * @param {Object} scope (optional)
26095 sort : function(fn, scope){
26096 var cs = this.childNodes;
26097 var len = cs.length;
26099 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
26101 for(var i = 0; i < len; i++){
26103 n.previousSibling = cs[i-1];
26104 n.nextSibling = cs[i+1];
26106 this.setFirstChild(n);
26109 this.setLastChild(n);
26116 * Returns true if this node is an ancestor (at any point) of the passed node.
26117 * @param {Node} node
26118 * @return {Boolean}
26120 contains : function(node){
26121 return node.isAncestor(this);
26125 * Returns true if the passed node is an ancestor (at any point) of this node.
26126 * @param {Node} node
26127 * @return {Boolean}
26129 isAncestor : function(node){
26130 var p = this.parentNode;
26140 toString : function(){
26141 return "[Node"+(this.id?" "+this.id:"")+"]";
26145 * Ext JS Library 1.1.1
26146 * Copyright(c) 2006-2007, Ext JS, LLC.
26148 * Originally Released Under LGPL - original licence link has changed is not relivant.
26151 * <script type="text/javascript">
26156 * @class Roo.Shadow
26157 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
26158 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
26159 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
26161 * Create a new Shadow
26162 * @param {Object} config The config object
26164 Roo.Shadow = function(config){
26165 Roo.apply(this, config);
26166 if(typeof this.mode != "string"){
26167 this.mode = this.defaultMode;
26169 var o = this.offset, a = {h: 0};
26170 var rad = Math.floor(this.offset/2);
26171 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
26177 a.l -= this.offset + rad;
26178 a.t -= this.offset + rad;
26189 a.l -= (this.offset - rad);
26190 a.t -= this.offset + rad;
26192 a.w -= (this.offset - rad)*2;
26203 a.l -= (this.offset - rad);
26204 a.t -= (this.offset - rad);
26206 a.w -= (this.offset + rad + 1);
26207 a.h -= (this.offset + rad);
26216 Roo.Shadow.prototype = {
26218 * @cfg {String} mode
26219 * The shadow display mode. Supports the following options:<br />
26220 * sides: Shadow displays on both sides and bottom only<br />
26221 * frame: Shadow displays equally on all four sides<br />
26222 * drop: Traditional bottom-right drop shadow (default)
26226 * @cfg {String} offset
26227 * The number of pixels to offset the shadow from the element (defaults to 4)
26232 defaultMode: "drop",
26235 * Displays the shadow under the target element
26236 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
26238 show : function(target){
26239 target = Roo.get(target);
26241 this.el = Roo.Shadow.Pool.pull();
26242 if(this.el.dom.nextSibling != target.dom){
26243 this.el.insertBefore(target);
26246 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
26248 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
26251 target.getLeft(true),
26252 target.getTop(true),
26256 this.el.dom.style.display = "block";
26260 * Returns true if the shadow is visible, else false
26262 isVisible : function(){
26263 return this.el ? true : false;
26267 * Direct alignment when values are already available. Show must be called at least once before
26268 * calling this method to ensure it is initialized.
26269 * @param {Number} left The target element left position
26270 * @param {Number} top The target element top position
26271 * @param {Number} width The target element width
26272 * @param {Number} height The target element height
26274 realign : function(l, t, w, h){
26278 var a = this.adjusts, d = this.el.dom, s = d.style;
26280 s.left = (l+a.l)+"px";
26281 s.top = (t+a.t)+"px";
26282 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
26284 if(s.width != sws || s.height != shs){
26288 var cn = d.childNodes;
26289 var sww = Math.max(0, (sw-12))+"px";
26290 cn[0].childNodes[1].style.width = sww;
26291 cn[1].childNodes[1].style.width = sww;
26292 cn[2].childNodes[1].style.width = sww;
26293 cn[1].style.height = Math.max(0, (sh-12))+"px";
26299 * Hides this shadow
26303 this.el.dom.style.display = "none";
26304 Roo.Shadow.Pool.push(this.el);
26310 * Adjust the z-index of this shadow
26311 * @param {Number} zindex The new z-index
26313 setZIndex : function(z){
26316 this.el.setStyle("z-index", z);
26321 // Private utility class that manages the internal Shadow cache
26322 Roo.Shadow.Pool = function(){
26324 var markup = Roo.isIE ?
26325 '<div class="x-ie-shadow"></div>' :
26326 '<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>';
26329 var sh = p.shift();
26331 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
26332 sh.autoBoxAdjust = false;
26337 push : function(sh){
26343 * Ext JS Library 1.1.1
26344 * Copyright(c) 2006-2007, Ext JS, LLC.
26346 * Originally Released Under LGPL - original licence link has changed is not relivant.
26349 * <script type="text/javascript">
26354 * @class Roo.SplitBar
26355 * @extends Roo.util.Observable
26356 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
26360 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
26361 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
26362 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
26363 split.minSize = 100;
26364 split.maxSize = 600;
26365 split.animate = true;
26366 split.on('moved', splitterMoved);
26369 * Create a new SplitBar
26370 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
26371 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
26372 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
26373 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
26374 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
26375 position of the SplitBar).
26377 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
26380 this.el = Roo.get(dragElement, true);
26381 this.el.dom.unselectable = "on";
26383 this.resizingEl = Roo.get(resizingElement, true);
26387 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
26388 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
26391 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
26394 * The minimum size of the resizing element. (Defaults to 0)
26400 * The maximum size of the resizing element. (Defaults to 2000)
26403 this.maxSize = 2000;
26406 * Whether to animate the transition to the new size
26409 this.animate = false;
26412 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
26415 this.useShim = false;
26420 if(!existingProxy){
26422 this.proxy = Roo.SplitBar.createProxy(this.orientation);
26424 this.proxy = Roo.get(existingProxy).dom;
26427 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
26430 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
26433 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
26436 this.dragSpecs = {};
26439 * @private The adapter to use to positon and resize elements
26441 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
26442 this.adapter.init(this);
26444 if(this.orientation == Roo.SplitBar.HORIZONTAL){
26446 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
26447 this.el.addClass("x-splitbar-h");
26450 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
26451 this.el.addClass("x-splitbar-v");
26457 * Fires when the splitter is moved (alias for {@link #event-moved})
26458 * @param {Roo.SplitBar} this
26459 * @param {Number} newSize the new width or height
26464 * Fires when the splitter is moved
26465 * @param {Roo.SplitBar} this
26466 * @param {Number} newSize the new width or height
26470 * @event beforeresize
26471 * Fires before the splitter is dragged
26472 * @param {Roo.SplitBar} this
26474 "beforeresize" : true,
26476 "beforeapply" : true
26479 Roo.util.Observable.call(this);
26482 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
26483 onStartProxyDrag : function(x, y){
26484 this.fireEvent("beforeresize", this);
26486 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
26488 o.enableDisplayMode("block");
26489 // all splitbars share the same overlay
26490 Roo.SplitBar.prototype.overlay = o;
26492 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
26493 this.overlay.show();
26494 Roo.get(this.proxy).setDisplayed("block");
26495 var size = this.adapter.getElementSize(this);
26496 this.activeMinSize = this.getMinimumSize();;
26497 this.activeMaxSize = this.getMaximumSize();;
26498 var c1 = size - this.activeMinSize;
26499 var c2 = Math.max(this.activeMaxSize - size, 0);
26500 if(this.orientation == Roo.SplitBar.HORIZONTAL){
26501 this.dd.resetConstraints();
26502 this.dd.setXConstraint(
26503 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
26504 this.placement == Roo.SplitBar.LEFT ? c2 : c1
26506 this.dd.setYConstraint(0, 0);
26508 this.dd.resetConstraints();
26509 this.dd.setXConstraint(0, 0);
26510 this.dd.setYConstraint(
26511 this.placement == Roo.SplitBar.TOP ? c1 : c2,
26512 this.placement == Roo.SplitBar.TOP ? c2 : c1
26515 this.dragSpecs.startSize = size;
26516 this.dragSpecs.startPoint = [x, y];
26517 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
26521 * @private Called after the drag operation by the DDProxy
26523 onEndProxyDrag : function(e){
26524 Roo.get(this.proxy).setDisplayed(false);
26525 var endPoint = Roo.lib.Event.getXY(e);
26527 this.overlay.hide();
26530 if(this.orientation == Roo.SplitBar.HORIZONTAL){
26531 newSize = this.dragSpecs.startSize +
26532 (this.placement == Roo.SplitBar.LEFT ?
26533 endPoint[0] - this.dragSpecs.startPoint[0] :
26534 this.dragSpecs.startPoint[0] - endPoint[0]
26537 newSize = this.dragSpecs.startSize +
26538 (this.placement == Roo.SplitBar.TOP ?
26539 endPoint[1] - this.dragSpecs.startPoint[1] :
26540 this.dragSpecs.startPoint[1] - endPoint[1]
26543 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
26544 if(newSize != this.dragSpecs.startSize){
26545 if(this.fireEvent('beforeapply', this, newSize) !== false){
26546 this.adapter.setElementSize(this, newSize);
26547 this.fireEvent("moved", this, newSize);
26548 this.fireEvent("resize", this, newSize);
26554 * Get the adapter this SplitBar uses
26555 * @return The adapter object
26557 getAdapter : function(){
26558 return this.adapter;
26562 * Set the adapter this SplitBar uses
26563 * @param {Object} adapter A SplitBar adapter object
26565 setAdapter : function(adapter){
26566 this.adapter = adapter;
26567 this.adapter.init(this);
26571 * Gets the minimum size for the resizing element
26572 * @return {Number} The minimum size
26574 getMinimumSize : function(){
26575 return this.minSize;
26579 * Sets the minimum size for the resizing element
26580 * @param {Number} minSize The minimum size
26582 setMinimumSize : function(minSize){
26583 this.minSize = minSize;
26587 * Gets the maximum size for the resizing element
26588 * @return {Number} The maximum size
26590 getMaximumSize : function(){
26591 return this.maxSize;
26595 * Sets the maximum size for the resizing element
26596 * @param {Number} maxSize The maximum size
26598 setMaximumSize : function(maxSize){
26599 this.maxSize = maxSize;
26603 * Sets the initialize size for the resizing element
26604 * @param {Number} size The initial size
26606 setCurrentSize : function(size){
26607 var oldAnimate = this.animate;
26608 this.animate = false;
26609 this.adapter.setElementSize(this, size);
26610 this.animate = oldAnimate;
26614 * Destroy this splitbar.
26615 * @param {Boolean} removeEl True to remove the element
26617 destroy : function(removeEl){
26619 this.shim.remove();
26622 this.proxy.parentNode.removeChild(this.proxy);
26630 * @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.
26632 Roo.SplitBar.createProxy = function(dir){
26633 var proxy = new Roo.Element(document.createElement("div"));
26634 proxy.unselectable();
26635 var cls = 'x-splitbar-proxy';
26636 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
26637 document.body.appendChild(proxy.dom);
26642 * @class Roo.SplitBar.BasicLayoutAdapter
26643 * Default Adapter. It assumes the splitter and resizing element are not positioned
26644 * elements and only gets/sets the width of the element. Generally used for table based layouts.
26646 Roo.SplitBar.BasicLayoutAdapter = function(){
26649 Roo.SplitBar.BasicLayoutAdapter.prototype = {
26650 // do nothing for now
26651 init : function(s){
26655 * Called before drag operations to get the current size of the resizing element.
26656 * @param {Roo.SplitBar} s The SplitBar using this adapter
26658 getElementSize : function(s){
26659 if(s.orientation == Roo.SplitBar.HORIZONTAL){
26660 return s.resizingEl.getWidth();
26662 return s.resizingEl.getHeight();
26667 * Called after drag operations to set the size of the resizing element.
26668 * @param {Roo.SplitBar} s The SplitBar using this adapter
26669 * @param {Number} newSize The new size to set
26670 * @param {Function} onComplete A function to be invoked when resizing is complete
26672 setElementSize : function(s, newSize, onComplete){
26673 if(s.orientation == Roo.SplitBar.HORIZONTAL){
26675 s.resizingEl.setWidth(newSize);
26677 onComplete(s, newSize);
26680 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
26685 s.resizingEl.setHeight(newSize);
26687 onComplete(s, newSize);
26690 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
26697 *@class Roo.SplitBar.AbsoluteLayoutAdapter
26698 * @extends Roo.SplitBar.BasicLayoutAdapter
26699 * Adapter that moves the splitter element to align with the resized sizing element.
26700 * Used with an absolute positioned SplitBar.
26701 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
26702 * document.body, make sure you assign an id to the body element.
26704 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
26705 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
26706 this.container = Roo.get(container);
26709 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
26710 init : function(s){
26711 this.basic.init(s);
26714 getElementSize : function(s){
26715 return this.basic.getElementSize(s);
26718 setElementSize : function(s, newSize, onComplete){
26719 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
26722 moveSplitter : function(s){
26723 var yes = Roo.SplitBar;
26724 switch(s.placement){
26726 s.el.setX(s.resizingEl.getRight());
26729 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
26732 s.el.setY(s.resizingEl.getBottom());
26735 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
26742 * Orientation constant - Create a vertical SplitBar
26746 Roo.SplitBar.VERTICAL = 1;
26749 * Orientation constant - Create a horizontal SplitBar
26753 Roo.SplitBar.HORIZONTAL = 2;
26756 * Placement constant - The resizing element is to the left of the splitter element
26760 Roo.SplitBar.LEFT = 1;
26763 * Placement constant - The resizing element is to the right of the splitter element
26767 Roo.SplitBar.RIGHT = 2;
26770 * Placement constant - The resizing element is positioned above the splitter element
26774 Roo.SplitBar.TOP = 3;
26777 * Placement constant - The resizing element is positioned under splitter element
26781 Roo.SplitBar.BOTTOM = 4;
26784 * Ext JS Library 1.1.1
26785 * Copyright(c) 2006-2007, Ext JS, LLC.
26787 * Originally Released Under LGPL - original licence link has changed is not relivant.
26790 * <script type="text/javascript">
26795 * @extends Roo.util.Observable
26796 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
26797 * This class also supports single and multi selection modes. <br>
26798 * Create a data model bound view:
26800 var store = new Roo.data.Store(...);
26802 var view = new Roo.View({
26804 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
26806 singleSelect: true,
26807 selectedClass: "ydataview-selected",
26811 // listen for node click?
26812 view.on("click", function(vw, index, node, e){
26813 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
26817 dataModel.load("foobar.xml");
26819 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
26821 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
26822 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
26824 * Note: old style constructor is still suported (container, template, config)
26827 * Create a new View
26828 * @param {Object} config The config object
26831 Roo.View = function(config, depreciated_tpl, depreciated_config){
26833 this.parent = false;
26835 if (typeof(depreciated_tpl) == 'undefined') {
26836 // new way.. - universal constructor.
26837 Roo.apply(this, config);
26838 this.el = Roo.get(this.el);
26841 this.el = Roo.get(config);
26842 this.tpl = depreciated_tpl;
26843 Roo.apply(this, depreciated_config);
26845 this.wrapEl = this.el.wrap().wrap();
26846 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
26849 if(typeof(this.tpl) == "string"){
26850 this.tpl = new Roo.Template(this.tpl);
26852 // support xtype ctors..
26853 this.tpl = new Roo.factory(this.tpl, Roo);
26857 this.tpl.compile();
26862 * @event beforeclick
26863 * Fires before a click is processed. Returns false to cancel the default action.
26864 * @param {Roo.View} this
26865 * @param {Number} index The index of the target node
26866 * @param {HTMLElement} node The target node
26867 * @param {Roo.EventObject} e The raw event object
26869 "beforeclick" : true,
26872 * Fires when a template node is clicked.
26873 * @param {Roo.View} this
26874 * @param {Number} index The index of the target node
26875 * @param {HTMLElement} node The target node
26876 * @param {Roo.EventObject} e The raw event object
26881 * Fires when a template node is double clicked.
26882 * @param {Roo.View} this
26883 * @param {Number} index The index of the target node
26884 * @param {HTMLElement} node The target node
26885 * @param {Roo.EventObject} e The raw event object
26889 * @event contextmenu
26890 * Fires when a template node is right clicked.
26891 * @param {Roo.View} this
26892 * @param {Number} index The index of the target node
26893 * @param {HTMLElement} node The target node
26894 * @param {Roo.EventObject} e The raw event object
26896 "contextmenu" : true,
26898 * @event selectionchange
26899 * Fires when the selected nodes change.
26900 * @param {Roo.View} this
26901 * @param {Array} selections Array of the selected nodes
26903 "selectionchange" : true,
26906 * @event beforeselect
26907 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
26908 * @param {Roo.View} this
26909 * @param {HTMLElement} node The node to be selected
26910 * @param {Array} selections Array of currently selected nodes
26912 "beforeselect" : true,
26914 * @event preparedata
26915 * Fires on every row to render, to allow you to change the data.
26916 * @param {Roo.View} this
26917 * @param {Object} data to be rendered (change this)
26919 "preparedata" : true
26927 "click": this.onClick,
26928 "dblclick": this.onDblClick,
26929 "contextmenu": this.onContextMenu,
26933 this.selections = [];
26935 this.cmp = new Roo.CompositeElementLite([]);
26937 this.store = Roo.factory(this.store, Roo.data);
26938 this.setStore(this.store, true);
26941 if ( this.footer && this.footer.xtype) {
26943 var fctr = this.wrapEl.appendChild(document.createElement("div"));
26945 this.footer.dataSource = this.store;
26946 this.footer.container = fctr;
26947 this.footer = Roo.factory(this.footer, Roo);
26948 fctr.insertFirst(this.el);
26950 // this is a bit insane - as the paging toolbar seems to detach the el..
26951 // dom.parentNode.parentNode.parentNode
26952 // they get detached?
26956 Roo.View.superclass.constructor.call(this);
26961 Roo.extend(Roo.View, Roo.util.Observable, {
26964 * @cfg {Roo.data.Store} store Data store to load data from.
26969 * @cfg {String|Roo.Element} el The container element.
26974 * @cfg {String|Roo.Template} tpl The template used by this View
26978 * @cfg {String} dataName the named area of the template to use as the data area
26979 * Works with domtemplates roo-name="name"
26983 * @cfg {String} selectedClass The css class to add to selected nodes
26985 selectedClass : "x-view-selected",
26987 * @cfg {String} emptyText The empty text to show when nothing is loaded.
26992 * @cfg {String} text to display on mask (default Loading)
26996 * @cfg {Boolean} multiSelect Allow multiple selection
26998 multiSelect : false,
27000 * @cfg {Boolean} singleSelect Allow single selection
27002 singleSelect: false,
27005 * @cfg {Boolean} toggleSelect - selecting
27007 toggleSelect : false,
27010 * @cfg {Boolean} tickable - selecting
27015 * Returns the element this view is bound to.
27016 * @return {Roo.Element}
27018 getEl : function(){
27019 return this.wrapEl;
27025 * Refreshes the view. - called by datachanged on the store. - do not call directly.
27027 refresh : function(){
27028 //Roo.log('refresh');
27031 // if we are using something like 'domtemplate', then
27032 // the what gets used is:
27033 // t.applySubtemplate(NAME, data, wrapping data..)
27034 // the outer template then get' applied with
27035 // the store 'extra data'
27036 // and the body get's added to the
27037 // roo-name="data" node?
27038 // <span class='roo-tpl-{name}'></span> ?????
27042 this.clearSelections();
27043 this.el.update("");
27045 var records = this.store.getRange();
27046 if(records.length < 1) {
27048 // is this valid?? = should it render a template??
27050 this.el.update(this.emptyText);
27054 if (this.dataName) {
27055 this.el.update(t.apply(this.store.meta)); //????
27056 el = this.el.child('.roo-tpl-' + this.dataName);
27059 for(var i = 0, len = records.length; i < len; i++){
27060 var data = this.prepareData(records[i].data, i, records[i]);
27061 this.fireEvent("preparedata", this, data, i, records[i]);
27063 var d = Roo.apply({}, data);
27066 Roo.apply(d, {'roo-id' : Roo.id()});
27070 Roo.each(this.parent.item, function(item){
27071 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
27074 Roo.apply(d, {'roo-data-checked' : 'checked'});
27078 html[html.length] = Roo.util.Format.trim(
27080 t.applySubtemplate(this.dataName, d, this.store.meta) :
27087 el.update(html.join(""));
27088 this.nodes = el.dom.childNodes;
27089 this.updateIndexes(0);
27094 * Function to override to reformat the data that is sent to
27095 * the template for each node.
27096 * DEPRICATED - use the preparedata event handler.
27097 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
27098 * a JSON object for an UpdateManager bound view).
27100 prepareData : function(data, index, record)
27102 this.fireEvent("preparedata", this, data, index, record);
27106 onUpdate : function(ds, record){
27107 // Roo.log('on update');
27108 this.clearSelections();
27109 var index = this.store.indexOf(record);
27110 var n = this.nodes[index];
27111 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
27112 n.parentNode.removeChild(n);
27113 this.updateIndexes(index, index);
27119 onAdd : function(ds, records, index)
27121 //Roo.log(['on Add', ds, records, index] );
27122 this.clearSelections();
27123 if(this.nodes.length == 0){
27127 var n = this.nodes[index];
27128 for(var i = 0, len = records.length; i < len; i++){
27129 var d = this.prepareData(records[i].data, i, records[i]);
27131 this.tpl.insertBefore(n, d);
27134 this.tpl.append(this.el, d);
27137 this.updateIndexes(index);
27140 onRemove : function(ds, record, index){
27141 // Roo.log('onRemove');
27142 this.clearSelections();
27143 var el = this.dataName ?
27144 this.el.child('.roo-tpl-' + this.dataName) :
27147 el.dom.removeChild(this.nodes[index]);
27148 this.updateIndexes(index);
27152 * Refresh an individual node.
27153 * @param {Number} index
27155 refreshNode : function(index){
27156 this.onUpdate(this.store, this.store.getAt(index));
27159 updateIndexes : function(startIndex, endIndex){
27160 var ns = this.nodes;
27161 startIndex = startIndex || 0;
27162 endIndex = endIndex || ns.length - 1;
27163 for(var i = startIndex; i <= endIndex; i++){
27164 ns[i].nodeIndex = i;
27169 * Changes the data store this view uses and refresh the view.
27170 * @param {Store} store
27172 setStore : function(store, initial){
27173 if(!initial && this.store){
27174 this.store.un("datachanged", this.refresh);
27175 this.store.un("add", this.onAdd);
27176 this.store.un("remove", this.onRemove);
27177 this.store.un("update", this.onUpdate);
27178 this.store.un("clear", this.refresh);
27179 this.store.un("beforeload", this.onBeforeLoad);
27180 this.store.un("load", this.onLoad);
27181 this.store.un("loadexception", this.onLoad);
27185 store.on("datachanged", this.refresh, this);
27186 store.on("add", this.onAdd, this);
27187 store.on("remove", this.onRemove, this);
27188 store.on("update", this.onUpdate, this);
27189 store.on("clear", this.refresh, this);
27190 store.on("beforeload", this.onBeforeLoad, this);
27191 store.on("load", this.onLoad, this);
27192 store.on("loadexception", this.onLoad, this);
27200 * onbeforeLoad - masks the loading area.
27203 onBeforeLoad : function(store,opts)
27205 //Roo.log('onBeforeLoad');
27207 this.el.update("");
27209 this.el.mask(this.mask ? this.mask : "Loading" );
27211 onLoad : function ()
27218 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
27219 * @param {HTMLElement} node
27220 * @return {HTMLElement} The template node
27222 findItemFromChild : function(node){
27223 var el = this.dataName ?
27224 this.el.child('.roo-tpl-' + this.dataName,true) :
27227 if(!node || node.parentNode == el){
27230 var p = node.parentNode;
27231 while(p && p != el){
27232 if(p.parentNode == el){
27241 onClick : function(e){
27242 var item = this.findItemFromChild(e.getTarget());
27244 var index = this.indexOf(item);
27245 if(this.onItemClick(item, index, e) !== false){
27246 this.fireEvent("click", this, index, item, e);
27249 this.clearSelections();
27254 onContextMenu : function(e){
27255 var item = this.findItemFromChild(e.getTarget());
27257 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
27262 onDblClick : function(e){
27263 var item = this.findItemFromChild(e.getTarget());
27265 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
27269 onItemClick : function(item, index, e)
27271 if(this.fireEvent("beforeclick", this, index, item, e) === false){
27274 if (this.toggleSelect) {
27275 var m = this.isSelected(item) ? 'unselect' : 'select';
27278 _t[m](item, true, false);
27281 if(this.multiSelect || this.singleSelect){
27282 if(this.multiSelect && e.shiftKey && this.lastSelection){
27283 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
27285 this.select(item, this.multiSelect && e.ctrlKey);
27286 this.lastSelection = item;
27289 if(!this.tickable){
27290 e.preventDefault();
27298 * Get the number of selected nodes.
27301 getSelectionCount : function(){
27302 return this.selections.length;
27306 * Get the currently selected nodes.
27307 * @return {Array} An array of HTMLElements
27309 getSelectedNodes : function(){
27310 return this.selections;
27314 * Get the indexes of the selected nodes.
27317 getSelectedIndexes : function(){
27318 var indexes = [], s = this.selections;
27319 for(var i = 0, len = s.length; i < len; i++){
27320 indexes.push(s[i].nodeIndex);
27326 * Clear all selections
27327 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
27329 clearSelections : function(suppressEvent){
27330 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
27331 this.cmp.elements = this.selections;
27332 this.cmp.removeClass(this.selectedClass);
27333 this.selections = [];
27334 if(!suppressEvent){
27335 this.fireEvent("selectionchange", this, this.selections);
27341 * Returns true if the passed node is selected
27342 * @param {HTMLElement/Number} node The node or node index
27343 * @return {Boolean}
27345 isSelected : function(node){
27346 var s = this.selections;
27350 node = this.getNode(node);
27351 return s.indexOf(node) !== -1;
27356 * @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
27357 * @param {Boolean} keepExisting (optional) true to keep existing selections
27358 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
27360 select : function(nodeInfo, keepExisting, suppressEvent){
27361 if(nodeInfo instanceof Array){
27363 this.clearSelections(true);
27365 for(var i = 0, len = nodeInfo.length; i < len; i++){
27366 this.select(nodeInfo[i], true, true);
27370 var node = this.getNode(nodeInfo);
27371 if(!node || this.isSelected(node)){
27372 return; // already selected.
27375 this.clearSelections(true);
27378 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
27379 Roo.fly(node).addClass(this.selectedClass);
27380 this.selections.push(node);
27381 if(!suppressEvent){
27382 this.fireEvent("selectionchange", this, this.selections);
27390 * @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
27391 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
27392 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
27394 unselect : function(nodeInfo, keepExisting, suppressEvent)
27396 if(nodeInfo instanceof Array){
27397 Roo.each(this.selections, function(s) {
27398 this.unselect(s, nodeInfo);
27402 var node = this.getNode(nodeInfo);
27403 if(!node || !this.isSelected(node)){
27404 //Roo.log("not selected");
27405 return; // not selected.
27409 Roo.each(this.selections, function(s) {
27411 Roo.fly(node).removeClass(this.selectedClass);
27418 this.selections= ns;
27419 this.fireEvent("selectionchange", this, this.selections);
27423 * Gets a template node.
27424 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
27425 * @return {HTMLElement} The node or null if it wasn't found
27427 getNode : function(nodeInfo){
27428 if(typeof nodeInfo == "string"){
27429 return document.getElementById(nodeInfo);
27430 }else if(typeof nodeInfo == "number"){
27431 return this.nodes[nodeInfo];
27437 * Gets a range template nodes.
27438 * @param {Number} startIndex
27439 * @param {Number} endIndex
27440 * @return {Array} An array of nodes
27442 getNodes : function(start, end){
27443 var ns = this.nodes;
27444 start = start || 0;
27445 end = typeof end == "undefined" ? ns.length - 1 : end;
27448 for(var i = start; i <= end; i++){
27452 for(var i = start; i >= end; i--){
27460 * Finds the index of the passed node
27461 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
27462 * @return {Number} The index of the node or -1
27464 indexOf : function(node){
27465 node = this.getNode(node);
27466 if(typeof node.nodeIndex == "number"){
27467 return node.nodeIndex;
27469 var ns = this.nodes;
27470 for(var i = 0, len = ns.length; i < len; i++){
27480 * Ext JS Library 1.1.1
27481 * Copyright(c) 2006-2007, Ext JS, LLC.
27483 * Originally Released Under LGPL - original licence link has changed is not relivant.
27486 * <script type="text/javascript">
27490 * @class Roo.JsonView
27491 * @extends Roo.View
27492 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
27494 var view = new Roo.JsonView({
27495 container: "my-element",
27496 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
27501 // listen for node click?
27502 view.on("click", function(vw, index, node, e){
27503 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
27506 // direct load of JSON data
27507 view.load("foobar.php");
27509 // Example from my blog list
27510 var tpl = new Roo.Template(
27511 '<div class="entry">' +
27512 '<a class="entry-title" href="{link}">{title}</a>' +
27513 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
27514 "</div><hr />"
27517 var moreView = new Roo.JsonView({
27518 container : "entry-list",
27522 moreView.on("beforerender", this.sortEntries, this);
27524 url: "/blog/get-posts.php",
27525 params: "allposts=true",
27526 text: "Loading Blog Entries..."
27530 * Note: old code is supported with arguments : (container, template, config)
27534 * Create a new JsonView
27536 * @param {Object} config The config object
27539 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
27542 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
27544 var um = this.el.getUpdateManager();
27545 um.setRenderer(this);
27546 um.on("update", this.onLoad, this);
27547 um.on("failure", this.onLoadException, this);
27550 * @event beforerender
27551 * Fires before rendering of the downloaded JSON data.
27552 * @param {Roo.JsonView} this
27553 * @param {Object} data The JSON data loaded
27557 * Fires when data is loaded.
27558 * @param {Roo.JsonView} this
27559 * @param {Object} data The JSON data loaded
27560 * @param {Object} response The raw Connect response object
27563 * @event loadexception
27564 * Fires when loading fails.
27565 * @param {Roo.JsonView} this
27566 * @param {Object} response The raw Connect response object
27569 'beforerender' : true,
27571 'loadexception' : true
27574 Roo.extend(Roo.JsonView, Roo.View, {
27576 * @type {String} The root property in the loaded JSON object that contains the data
27581 * Refreshes the view.
27583 refresh : function(){
27584 this.clearSelections();
27585 this.el.update("");
27587 var o = this.jsonData;
27588 if(o && o.length > 0){
27589 for(var i = 0, len = o.length; i < len; i++){
27590 var data = this.prepareData(o[i], i, o);
27591 html[html.length] = this.tpl.apply(data);
27594 html.push(this.emptyText);
27596 this.el.update(html.join(""));
27597 this.nodes = this.el.dom.childNodes;
27598 this.updateIndexes(0);
27602 * 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.
27603 * @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:
27606 url: "your-url.php",
27607 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
27608 callback: yourFunction,
27609 scope: yourObject, //(optional scope)
27612 text: "Loading...",
27617 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
27618 * 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.
27619 * @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}
27620 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
27621 * @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.
27624 var um = this.el.getUpdateManager();
27625 um.update.apply(um, arguments);
27628 // note - render is a standard framework call...
27629 // using it for the response is really flaky... - it's called by UpdateManager normally, except when called by the XComponent/addXtype.
27630 render : function(el, response){
27632 this.clearSelections();
27633 this.el.update("");
27636 if (response != '') {
27637 o = Roo.util.JSON.decode(response.responseText);
27640 o = o[this.jsonRoot];
27646 * The current JSON data or null
27649 this.beforeRender();
27654 * Get the number of records in the current JSON dataset
27657 getCount : function(){
27658 return this.jsonData ? this.jsonData.length : 0;
27662 * Returns the JSON object for the specified node(s)
27663 * @param {HTMLElement/Array} node The node or an array of nodes
27664 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
27665 * you get the JSON object for the node
27667 getNodeData : function(node){
27668 if(node instanceof Array){
27670 for(var i = 0, len = node.length; i < len; i++){
27671 data.push(this.getNodeData(node[i]));
27675 return this.jsonData[this.indexOf(node)] || null;
27678 beforeRender : function(){
27679 this.snapshot = this.jsonData;
27681 this.sort.apply(this, this.sortInfo);
27683 this.fireEvent("beforerender", this, this.jsonData);
27686 onLoad : function(el, o){
27687 this.fireEvent("load", this, this.jsonData, o);
27690 onLoadException : function(el, o){
27691 this.fireEvent("loadexception", this, o);
27695 * Filter the data by a specific property.
27696 * @param {String} property A property on your JSON objects
27697 * @param {String/RegExp} value Either string that the property values
27698 * should start with, or a RegExp to test against the property
27700 filter : function(property, value){
27703 var ss = this.snapshot;
27704 if(typeof value == "string"){
27705 var vlen = value.length;
27707 this.clearFilter();
27710 value = value.toLowerCase();
27711 for(var i = 0, len = ss.length; i < len; i++){
27713 if(o[property].substr(0, vlen).toLowerCase() == value){
27717 } else if(value.exec){ // regex?
27718 for(var i = 0, len = ss.length; i < len; i++){
27720 if(value.test(o[property])){
27727 this.jsonData = data;
27733 * Filter by a function. The passed function will be called with each
27734 * object in the current dataset. If the function returns true the value is kept,
27735 * otherwise it is filtered.
27736 * @param {Function} fn
27737 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
27739 filterBy : function(fn, scope){
27742 var ss = this.snapshot;
27743 for(var i = 0, len = ss.length; i < len; i++){
27745 if(fn.call(scope || this, o)){
27749 this.jsonData = data;
27755 * Clears the current filter.
27757 clearFilter : function(){
27758 if(this.snapshot && this.jsonData != this.snapshot){
27759 this.jsonData = this.snapshot;
27766 * Sorts the data for this view and refreshes it.
27767 * @param {String} property A property on your JSON objects to sort on
27768 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
27769 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
27771 sort : function(property, dir, sortType){
27772 this.sortInfo = Array.prototype.slice.call(arguments, 0);
27775 var dsc = dir && dir.toLowerCase() == "desc";
27776 var f = function(o1, o2){
27777 var v1 = sortType ? sortType(o1[p]) : o1[p];
27778 var v2 = sortType ? sortType(o2[p]) : o2[p];
27781 return dsc ? +1 : -1;
27782 } else if(v1 > v2){
27783 return dsc ? -1 : +1;
27788 this.jsonData.sort(f);
27790 if(this.jsonData != this.snapshot){
27791 this.snapshot.sort(f);
27797 * Ext JS Library 1.1.1
27798 * Copyright(c) 2006-2007, Ext JS, LLC.
27800 * Originally Released Under LGPL - original licence link has changed is not relivant.
27803 * <script type="text/javascript">
27808 * @class Roo.ColorPalette
27809 * @extends Roo.Component
27810 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
27811 * Here's an example of typical usage:
27813 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
27814 cp.render('my-div');
27816 cp.on('select', function(palette, selColor){
27817 // do something with selColor
27821 * Create a new ColorPalette
27822 * @param {Object} config The config object
27824 Roo.ColorPalette = function(config){
27825 Roo.ColorPalette.superclass.constructor.call(this, config);
27829 * Fires when a color is selected
27830 * @param {ColorPalette} this
27831 * @param {String} color The 6-digit color hex code (without the # symbol)
27837 this.on("select", this.handler, this.scope, true);
27840 Roo.extend(Roo.ColorPalette, Roo.Component, {
27842 * @cfg {String} itemCls
27843 * The CSS class to apply to the containing element (defaults to "x-color-palette")
27845 itemCls : "x-color-palette",
27847 * @cfg {String} value
27848 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
27849 * the hex codes are case-sensitive.
27852 clickEvent:'click',
27854 ctype: "Roo.ColorPalette",
27857 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
27859 allowReselect : false,
27862 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
27863 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
27864 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
27865 * of colors with the width setting until the box is symmetrical.</p>
27866 * <p>You can override individual colors if needed:</p>
27868 var cp = new Roo.ColorPalette();
27869 cp.colors[0] = "FF0000"; // change the first box to red
27872 Or you can provide a custom array of your own for complete control:
27874 var cp = new Roo.ColorPalette();
27875 cp.colors = ["000000", "993300", "333300"];
27880 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
27881 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
27882 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
27883 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
27884 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
27888 onRender : function(container, position){
27889 var t = new Roo.MasterTemplate(
27890 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
27892 var c = this.colors;
27893 for(var i = 0, len = c.length; i < len; i++){
27896 var el = document.createElement("div");
27897 el.className = this.itemCls;
27899 container.dom.insertBefore(el, position);
27900 this.el = Roo.get(el);
27901 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
27902 if(this.clickEvent != 'click'){
27903 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
27908 afterRender : function(){
27909 Roo.ColorPalette.superclass.afterRender.call(this);
27911 var s = this.value;
27918 handleClick : function(e, t){
27919 e.preventDefault();
27920 if(!this.disabled){
27921 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
27922 this.select(c.toUpperCase());
27927 * Selects the specified color in the palette (fires the select event)
27928 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
27930 select : function(color){
27931 color = color.replace("#", "");
27932 if(color != this.value || this.allowReselect){
27935 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
27937 el.child("a.color-"+color).addClass("x-color-palette-sel");
27938 this.value = color;
27939 this.fireEvent("select", this, color);
27944 * Ext JS Library 1.1.1
27945 * Copyright(c) 2006-2007, Ext JS, LLC.
27947 * Originally Released Under LGPL - original licence link has changed is not relivant.
27950 * <script type="text/javascript">
27954 * @class Roo.DatePicker
27955 * @extends Roo.Component
27956 * Simple date picker class.
27958 * Create a new DatePicker
27959 * @param {Object} config The config object
27961 Roo.DatePicker = function(config){
27962 Roo.DatePicker.superclass.constructor.call(this, config);
27964 this.value = config && config.value ?
27965 config.value.clearTime() : new Date().clearTime();
27970 * Fires when a date is selected
27971 * @param {DatePicker} this
27972 * @param {Date} date The selected date
27976 * @event monthchange
27977 * Fires when the displayed month changes
27978 * @param {DatePicker} this
27979 * @param {Date} date The selected month
27981 'monthchange': true
27985 this.on("select", this.handler, this.scope || this);
27987 // build the disabledDatesRE
27988 if(!this.disabledDatesRE && this.disabledDates){
27989 var dd = this.disabledDates;
27991 for(var i = 0; i < dd.length; i++){
27993 if(i != dd.length-1) {
27997 this.disabledDatesRE = new RegExp(re + ")");
28001 Roo.extend(Roo.DatePicker, Roo.Component, {
28003 * @cfg {String} todayText
28004 * The text to display on the button that selects the current date (defaults to "Today")
28006 todayText : "Today",
28008 * @cfg {String} okText
28009 * The text to display on the ok button
28011 okText : " OK ", //   to give the user extra clicking room
28013 * @cfg {String} cancelText
28014 * The text to display on the cancel button
28016 cancelText : "Cancel",
28018 * @cfg {String} todayTip
28019 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
28021 todayTip : "{0} (Spacebar)",
28023 * @cfg {Date} minDate
28024 * Minimum allowable date (JavaScript date object, defaults to null)
28028 * @cfg {Date} maxDate
28029 * Maximum allowable date (JavaScript date object, defaults to null)
28033 * @cfg {String} minText
28034 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
28036 minText : "This date is before the minimum date",
28038 * @cfg {String} maxText
28039 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
28041 maxText : "This date is after the maximum date",
28043 * @cfg {String} format
28044 * The default date format string which can be overriden for localization support. The format must be
28045 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
28049 * @cfg {Array} disabledDays
28050 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
28052 disabledDays : null,
28054 * @cfg {String} disabledDaysText
28055 * The tooltip to display when the date falls on a disabled day (defaults to "")
28057 disabledDaysText : "",
28059 * @cfg {RegExp} disabledDatesRE
28060 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
28062 disabledDatesRE : null,
28064 * @cfg {String} disabledDatesText
28065 * The tooltip text to display when the date falls on a disabled date (defaults to "")
28067 disabledDatesText : "",
28069 * @cfg {Boolean} constrainToViewport
28070 * True to constrain the date picker to the viewport (defaults to true)
28072 constrainToViewport : true,
28074 * @cfg {Array} monthNames
28075 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
28077 monthNames : Date.monthNames,
28079 * @cfg {Array} dayNames
28080 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
28082 dayNames : Date.dayNames,
28084 * @cfg {String} nextText
28085 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
28087 nextText: 'Next Month (Control+Right)',
28089 * @cfg {String} prevText
28090 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
28092 prevText: 'Previous Month (Control+Left)',
28094 * @cfg {String} monthYearText
28095 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
28097 monthYearText: 'Choose a month (Control+Up/Down to move years)',
28099 * @cfg {Number} startDay
28100 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
28104 * @cfg {Bool} showClear
28105 * Show a clear button (usefull for date form elements that can be blank.)
28111 * Sets the value of the date field
28112 * @param {Date} value The date to set
28114 setValue : function(value){
28115 var old = this.value;
28117 if (typeof(value) == 'string') {
28119 value = Date.parseDate(value, this.format);
28122 value = new Date();
28125 this.value = value.clearTime(true);
28127 this.update(this.value);
28132 * Gets the current selected value of the date field
28133 * @return {Date} The selected date
28135 getValue : function(){
28140 focus : function(){
28142 this.update(this.activeDate);
28147 onRender : function(container, position){
28150 '<table cellspacing="0">',
28151 '<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>',
28152 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
28153 var dn = this.dayNames;
28154 for(var i = 0; i < 7; i++){
28155 var d = this.startDay+i;
28159 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
28161 m[m.length] = "</tr></thead><tbody><tr>";
28162 for(var i = 0; i < 42; i++) {
28163 if(i % 7 == 0 && i != 0){
28164 m[m.length] = "</tr><tr>";
28166 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
28168 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
28169 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
28171 var el = document.createElement("div");
28172 el.className = "x-date-picker";
28173 el.innerHTML = m.join("");
28175 container.dom.insertBefore(el, position);
28177 this.el = Roo.get(el);
28178 this.eventEl = Roo.get(el.firstChild);
28180 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
28181 handler: this.showPrevMonth,
28183 preventDefault:true,
28187 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
28188 handler: this.showNextMonth,
28190 preventDefault:true,
28194 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
28196 this.monthPicker = this.el.down('div.x-date-mp');
28197 this.monthPicker.enableDisplayMode('block');
28199 var kn = new Roo.KeyNav(this.eventEl, {
28200 "left" : function(e){
28202 this.showPrevMonth() :
28203 this.update(this.activeDate.add("d", -1));
28206 "right" : function(e){
28208 this.showNextMonth() :
28209 this.update(this.activeDate.add("d", 1));
28212 "up" : function(e){
28214 this.showNextYear() :
28215 this.update(this.activeDate.add("d", -7));
28218 "down" : function(e){
28220 this.showPrevYear() :
28221 this.update(this.activeDate.add("d", 7));
28224 "pageUp" : function(e){
28225 this.showNextMonth();
28228 "pageDown" : function(e){
28229 this.showPrevMonth();
28232 "enter" : function(e){
28233 e.stopPropagation();
28240 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
28242 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
28244 this.el.unselectable();
28246 this.cells = this.el.select("table.x-date-inner tbody td");
28247 this.textNodes = this.el.query("table.x-date-inner tbody span");
28249 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
28251 tooltip: this.monthYearText
28254 this.mbtn.on('click', this.showMonthPicker, this);
28255 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
28258 var today = (new Date()).dateFormat(this.format);
28260 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
28261 if (this.showClear) {
28262 baseTb.add( new Roo.Toolbar.Fill());
28265 text: String.format(this.todayText, today),
28266 tooltip: String.format(this.todayTip, today),
28267 handler: this.selectToday,
28271 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
28274 if (this.showClear) {
28276 baseTb.add( new Roo.Toolbar.Fill());
28279 cls: 'x-btn-icon x-btn-clear',
28280 handler: function() {
28282 this.fireEvent("select", this, '');
28292 this.update(this.value);
28295 createMonthPicker : function(){
28296 if(!this.monthPicker.dom.firstChild){
28297 var buf = ['<table border="0" cellspacing="0">'];
28298 for(var i = 0; i < 6; i++){
28300 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
28301 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
28303 '<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>' :
28304 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
28308 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
28310 '</button><button type="button" class="x-date-mp-cancel">',
28312 '</button></td></tr>',
28315 this.monthPicker.update(buf.join(''));
28316 this.monthPicker.on('click', this.onMonthClick, this);
28317 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
28319 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
28320 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
28322 this.mpMonths.each(function(m, a, i){
28325 m.dom.xmonth = 5 + Math.round(i * .5);
28327 m.dom.xmonth = Math.round((i-1) * .5);
28333 showMonthPicker : function(){
28334 this.createMonthPicker();
28335 var size = this.el.getSize();
28336 this.monthPicker.setSize(size);
28337 this.monthPicker.child('table').setSize(size);
28339 this.mpSelMonth = (this.activeDate || this.value).getMonth();
28340 this.updateMPMonth(this.mpSelMonth);
28341 this.mpSelYear = (this.activeDate || this.value).getFullYear();
28342 this.updateMPYear(this.mpSelYear);
28344 this.monthPicker.slideIn('t', {duration:.2});
28347 updateMPYear : function(y){
28349 var ys = this.mpYears.elements;
28350 for(var i = 1; i <= 10; i++){
28351 var td = ys[i-1], y2;
28353 y2 = y + Math.round(i * .5);
28354 td.firstChild.innerHTML = y2;
28357 y2 = y - (5-Math.round(i * .5));
28358 td.firstChild.innerHTML = y2;
28361 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
28365 updateMPMonth : function(sm){
28366 this.mpMonths.each(function(m, a, i){
28367 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
28371 selectMPMonth: function(m){
28375 onMonthClick : function(e, t){
28377 var el = new Roo.Element(t), pn;
28378 if(el.is('button.x-date-mp-cancel')){
28379 this.hideMonthPicker();
28381 else if(el.is('button.x-date-mp-ok')){
28382 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
28383 this.hideMonthPicker();
28385 else if(pn = el.up('td.x-date-mp-month', 2)){
28386 this.mpMonths.removeClass('x-date-mp-sel');
28387 pn.addClass('x-date-mp-sel');
28388 this.mpSelMonth = pn.dom.xmonth;
28390 else if(pn = el.up('td.x-date-mp-year', 2)){
28391 this.mpYears.removeClass('x-date-mp-sel');
28392 pn.addClass('x-date-mp-sel');
28393 this.mpSelYear = pn.dom.xyear;
28395 else if(el.is('a.x-date-mp-prev')){
28396 this.updateMPYear(this.mpyear-10);
28398 else if(el.is('a.x-date-mp-next')){
28399 this.updateMPYear(this.mpyear+10);
28403 onMonthDblClick : function(e, t){
28405 var el = new Roo.Element(t), pn;
28406 if(pn = el.up('td.x-date-mp-month', 2)){
28407 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
28408 this.hideMonthPicker();
28410 else if(pn = el.up('td.x-date-mp-year', 2)){
28411 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
28412 this.hideMonthPicker();
28416 hideMonthPicker : function(disableAnim){
28417 if(this.monthPicker){
28418 if(disableAnim === true){
28419 this.monthPicker.hide();
28421 this.monthPicker.slideOut('t', {duration:.2});
28427 showPrevMonth : function(e){
28428 this.update(this.activeDate.add("mo", -1));
28432 showNextMonth : function(e){
28433 this.update(this.activeDate.add("mo", 1));
28437 showPrevYear : function(){
28438 this.update(this.activeDate.add("y", -1));
28442 showNextYear : function(){
28443 this.update(this.activeDate.add("y", 1));
28447 handleMouseWheel : function(e){
28448 var delta = e.getWheelDelta();
28450 this.showPrevMonth();
28452 } else if(delta < 0){
28453 this.showNextMonth();
28459 handleDateClick : function(e, t){
28461 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
28462 this.setValue(new Date(t.dateValue));
28463 this.fireEvent("select", this, this.value);
28468 selectToday : function(){
28469 this.setValue(new Date().clearTime());
28470 this.fireEvent("select", this, this.value);
28474 update : function(date)
28476 var vd = this.activeDate;
28477 this.activeDate = date;
28479 var t = date.getTime();
28480 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
28481 this.cells.removeClass("x-date-selected");
28482 this.cells.each(function(c){
28483 if(c.dom.firstChild.dateValue == t){
28484 c.addClass("x-date-selected");
28485 setTimeout(function(){
28486 try{c.dom.firstChild.focus();}catch(e){}
28495 var days = date.getDaysInMonth();
28496 var firstOfMonth = date.getFirstDateOfMonth();
28497 var startingPos = firstOfMonth.getDay()-this.startDay;
28499 if(startingPos <= this.startDay){
28503 var pm = date.add("mo", -1);
28504 var prevStart = pm.getDaysInMonth()-startingPos;
28506 var cells = this.cells.elements;
28507 var textEls = this.textNodes;
28508 days += startingPos;
28510 // convert everything to numbers so it's fast
28511 var day = 86400000;
28512 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
28513 var today = new Date().clearTime().getTime();
28514 var sel = date.clearTime().getTime();
28515 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
28516 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
28517 var ddMatch = this.disabledDatesRE;
28518 var ddText = this.disabledDatesText;
28519 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
28520 var ddaysText = this.disabledDaysText;
28521 var format = this.format;
28523 var setCellClass = function(cal, cell){
28525 var t = d.getTime();
28526 cell.firstChild.dateValue = t;
28528 cell.className += " x-date-today";
28529 cell.title = cal.todayText;
28532 cell.className += " x-date-selected";
28533 setTimeout(function(){
28534 try{cell.firstChild.focus();}catch(e){}
28539 cell.className = " x-date-disabled";
28540 cell.title = cal.minText;
28544 cell.className = " x-date-disabled";
28545 cell.title = cal.maxText;
28549 if(ddays.indexOf(d.getDay()) != -1){
28550 cell.title = ddaysText;
28551 cell.className = " x-date-disabled";
28554 if(ddMatch && format){
28555 var fvalue = d.dateFormat(format);
28556 if(ddMatch.test(fvalue)){
28557 cell.title = ddText.replace("%0", fvalue);
28558 cell.className = " x-date-disabled";
28564 for(; i < startingPos; i++) {
28565 textEls[i].innerHTML = (++prevStart);
28566 d.setDate(d.getDate()+1);
28567 cells[i].className = "x-date-prevday";
28568 setCellClass(this, cells[i]);
28570 for(; i < days; i++){
28571 intDay = i - startingPos + 1;
28572 textEls[i].innerHTML = (intDay);
28573 d.setDate(d.getDate()+1);
28574 cells[i].className = "x-date-active";
28575 setCellClass(this, cells[i]);
28578 for(; i < 42; i++) {
28579 textEls[i].innerHTML = (++extraDays);
28580 d.setDate(d.getDate()+1);
28581 cells[i].className = "x-date-nextday";
28582 setCellClass(this, cells[i]);
28585 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
28586 this.fireEvent('monthchange', this, date);
28588 if(!this.internalRender){
28589 var main = this.el.dom.firstChild;
28590 var w = main.offsetWidth;
28591 this.el.setWidth(w + this.el.getBorderWidth("lr"));
28592 Roo.fly(main).setWidth(w);
28593 this.internalRender = true;
28594 // opera does not respect the auto grow header center column
28595 // then, after it gets a width opera refuses to recalculate
28596 // without a second pass
28597 if(Roo.isOpera && !this.secondPass){
28598 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
28599 this.secondPass = true;
28600 this.update.defer(10, this, [date]);
28608 * Ext JS Library 1.1.1
28609 * Copyright(c) 2006-2007, Ext JS, LLC.
28611 * Originally Released Under LGPL - original licence link has changed is not relivant.
28614 * <script type="text/javascript">
28617 * @class Roo.TabPanel
28618 * @extends Roo.util.Observable
28619 * A lightweight tab container.
28623 // basic tabs 1, built from existing content
28624 var tabs = new Roo.TabPanel("tabs1");
28625 tabs.addTab("script", "View Script");
28626 tabs.addTab("markup", "View Markup");
28627 tabs.activate("script");
28629 // more advanced tabs, built from javascript
28630 var jtabs = new Roo.TabPanel("jtabs");
28631 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
28633 // set up the UpdateManager
28634 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
28635 var updater = tab2.getUpdateManager();
28636 updater.setDefaultUrl("ajax1.htm");
28637 tab2.on('activate', updater.refresh, updater, true);
28639 // Use setUrl for Ajax loading
28640 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
28641 tab3.setUrl("ajax2.htm", null, true);
28644 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
28647 jtabs.activate("jtabs-1");
28650 * Create a new TabPanel.
28651 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
28652 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
28654 Roo.TabPanel = function(container, config){
28656 * The container element for this TabPanel.
28657 * @type Roo.Element
28659 this.el = Roo.get(container, true);
28661 if(typeof config == "boolean"){
28662 this.tabPosition = config ? "bottom" : "top";
28664 Roo.apply(this, config);
28667 if(this.tabPosition == "bottom"){
28668 this.bodyEl = Roo.get(this.createBody(this.el.dom));
28669 this.el.addClass("x-tabs-bottom");
28671 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
28672 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
28673 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
28675 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
28677 if(this.tabPosition != "bottom"){
28678 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
28679 * @type Roo.Element
28681 this.bodyEl = Roo.get(this.createBody(this.el.dom));
28682 this.el.addClass("x-tabs-top");
28686 this.bodyEl.setStyle("position", "relative");
28688 this.active = null;
28689 this.activateDelegate = this.activate.createDelegate(this);
28694 * Fires when the active tab changes
28695 * @param {Roo.TabPanel} this
28696 * @param {Roo.TabPanelItem} activePanel The new active tab
28700 * @event beforetabchange
28701 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
28702 * @param {Roo.TabPanel} this
28703 * @param {Object} e Set cancel to true on this object to cancel the tab change
28704 * @param {Roo.TabPanelItem} tab The tab being changed to
28706 "beforetabchange" : true
28709 Roo.EventManager.onWindowResize(this.onResize, this);
28710 this.cpad = this.el.getPadding("lr");
28711 this.hiddenCount = 0;
28714 // toolbar on the tabbar support...
28715 if (this.toolbar) {
28716 var tcfg = this.toolbar;
28717 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
28718 this.toolbar = new Roo.Toolbar(tcfg);
28719 if (Roo.isSafari) {
28720 var tbl = tcfg.container.child('table', true);
28721 tbl.setAttribute('width', '100%');
28728 Roo.TabPanel.superclass.constructor.call(this);
28731 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
28733 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
28735 tabPosition : "top",
28737 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
28739 currentTabWidth : 0,
28741 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
28745 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
28749 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
28751 preferredTabWidth : 175,
28753 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
28755 resizeTabs : false,
28757 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
28759 monitorResize : true,
28761 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
28766 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
28767 * @param {String} id The id of the div to use <b>or create</b>
28768 * @param {String} text The text for the tab
28769 * @param {String} content (optional) Content to put in the TabPanelItem body
28770 * @param {Boolean} closable (optional) True to create a close icon on the tab
28771 * @return {Roo.TabPanelItem} The created TabPanelItem
28773 addTab : function(id, text, content, closable){
28774 var item = new Roo.TabPanelItem(this, id, text, closable);
28775 this.addTabItem(item);
28777 item.setContent(content);
28783 * Returns the {@link Roo.TabPanelItem} with the specified id/index
28784 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
28785 * @return {Roo.TabPanelItem}
28787 getTab : function(id){
28788 return this.items[id];
28792 * Hides the {@link Roo.TabPanelItem} with the specified id/index
28793 * @param {String/Number} id The id or index of the TabPanelItem to hide.
28795 hideTab : function(id){
28796 var t = this.items[id];
28799 this.hiddenCount++;
28800 this.autoSizeTabs();
28805 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
28806 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
28808 unhideTab : function(id){
28809 var t = this.items[id];
28811 t.setHidden(false);
28812 this.hiddenCount--;
28813 this.autoSizeTabs();
28818 * Adds an existing {@link Roo.TabPanelItem}.
28819 * @param {Roo.TabPanelItem} item The TabPanelItem to add
28821 addTabItem : function(item){
28822 this.items[item.id] = item;
28823 this.items.push(item);
28824 if(this.resizeTabs){
28825 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
28826 this.autoSizeTabs();
28833 * Removes a {@link Roo.TabPanelItem}.
28834 * @param {String/Number} id The id or index of the TabPanelItem to remove.
28836 removeTab : function(id){
28837 var items = this.items;
28838 var tab = items[id];
28839 if(!tab) { return; }
28840 var index = items.indexOf(tab);
28841 if(this.active == tab && items.length > 1){
28842 var newTab = this.getNextAvailable(index);
28847 this.stripEl.dom.removeChild(tab.pnode.dom);
28848 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
28849 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
28851 items.splice(index, 1);
28852 delete this.items[tab.id];
28853 tab.fireEvent("close", tab);
28854 tab.purgeListeners();
28855 this.autoSizeTabs();
28858 getNextAvailable : function(start){
28859 var items = this.items;
28861 // look for a next tab that will slide over to
28862 // replace the one being removed
28863 while(index < items.length){
28864 var item = items[++index];
28865 if(item && !item.isHidden()){
28869 // if one isn't found select the previous tab (on the left)
28872 var item = items[--index];
28873 if(item && !item.isHidden()){
28881 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
28882 * @param {String/Number} id The id or index of the TabPanelItem to disable.
28884 disableTab : function(id){
28885 var tab = this.items[id];
28886 if(tab && this.active != tab){
28892 * Enables a {@link Roo.TabPanelItem} that is disabled.
28893 * @param {String/Number} id The id or index of the TabPanelItem to enable.
28895 enableTab : function(id){
28896 var tab = this.items[id];
28901 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
28902 * @param {String/Number} id The id or index of the TabPanelItem to activate.
28903 * @return {Roo.TabPanelItem} The TabPanelItem.
28905 activate : function(id){
28906 var tab = this.items[id];
28910 if(tab == this.active || tab.disabled){
28914 this.fireEvent("beforetabchange", this, e, tab);
28915 if(e.cancel !== true && !tab.disabled){
28917 this.active.hide();
28919 this.active = this.items[id];
28920 this.active.show();
28921 this.fireEvent("tabchange", this, this.active);
28927 * Gets the active {@link Roo.TabPanelItem}.
28928 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
28930 getActiveTab : function(){
28931 return this.active;
28935 * Updates the tab body element to fit the height of the container element
28936 * for overflow scrolling
28937 * @param {Number} targetHeight (optional) Override the starting height from the elements height
28939 syncHeight : function(targetHeight){
28940 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
28941 var bm = this.bodyEl.getMargins();
28942 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
28943 this.bodyEl.setHeight(newHeight);
28947 onResize : function(){
28948 if(this.monitorResize){
28949 this.autoSizeTabs();
28954 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
28956 beginUpdate : function(){
28957 this.updating = true;
28961 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
28963 endUpdate : function(){
28964 this.updating = false;
28965 this.autoSizeTabs();
28969 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
28971 autoSizeTabs : function(){
28972 var count = this.items.length;
28973 var vcount = count - this.hiddenCount;
28974 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
28977 var w = Math.max(this.el.getWidth() - this.cpad, 10);
28978 var availWidth = Math.floor(w / vcount);
28979 var b = this.stripBody;
28980 if(b.getWidth() > w){
28981 var tabs = this.items;
28982 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
28983 if(availWidth < this.minTabWidth){
28984 /*if(!this.sleft){ // incomplete scrolling code
28985 this.createScrollButtons();
28988 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
28991 if(this.currentTabWidth < this.preferredTabWidth){
28992 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
28998 * Returns the number of tabs in this TabPanel.
29001 getCount : function(){
29002 return this.items.length;
29006 * Resizes all the tabs to the passed width
29007 * @param {Number} The new width
29009 setTabWidth : function(width){
29010 this.currentTabWidth = width;
29011 for(var i = 0, len = this.items.length; i < len; i++) {
29012 if(!this.items[i].isHidden()) {
29013 this.items[i].setWidth(width);
29019 * Destroys this TabPanel
29020 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
29022 destroy : function(removeEl){
29023 Roo.EventManager.removeResizeListener(this.onResize, this);
29024 for(var i = 0, len = this.items.length; i < len; i++){
29025 this.items[i].purgeListeners();
29027 if(removeEl === true){
29028 this.el.update("");
29035 * @class Roo.TabPanelItem
29036 * @extends Roo.util.Observable
29037 * Represents an individual item (tab plus body) in a TabPanel.
29038 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
29039 * @param {String} id The id of this TabPanelItem
29040 * @param {String} text The text for the tab of this TabPanelItem
29041 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
29043 Roo.TabPanelItem = function(tabPanel, id, text, closable){
29045 * The {@link Roo.TabPanel} this TabPanelItem belongs to
29046 * @type Roo.TabPanel
29048 this.tabPanel = tabPanel;
29050 * The id for this TabPanelItem
29055 this.disabled = false;
29059 this.loaded = false;
29060 this.closable = closable;
29063 * The body element for this TabPanelItem.
29064 * @type Roo.Element
29066 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
29067 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
29068 this.bodyEl.setStyle("display", "block");
29069 this.bodyEl.setStyle("zoom", "1");
29072 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
29074 this.el = Roo.get(els.el, true);
29075 this.inner = Roo.get(els.inner, true);
29076 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
29077 this.pnode = Roo.get(els.el.parentNode, true);
29078 this.el.on("mousedown", this.onTabMouseDown, this);
29079 this.el.on("click", this.onTabClick, this);
29082 var c = Roo.get(els.close, true);
29083 c.dom.title = this.closeText;
29084 c.addClassOnOver("close-over");
29085 c.on("click", this.closeClick, this);
29091 * Fires when this tab becomes the active tab.
29092 * @param {Roo.TabPanel} tabPanel The parent TabPanel
29093 * @param {Roo.TabPanelItem} this
29097 * @event beforeclose
29098 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
29099 * @param {Roo.TabPanelItem} this
29100 * @param {Object} e Set cancel to true on this object to cancel the close.
29102 "beforeclose": true,
29105 * Fires when this tab is closed.
29106 * @param {Roo.TabPanelItem} this
29110 * @event deactivate
29111 * Fires when this tab is no longer the active tab.
29112 * @param {Roo.TabPanel} tabPanel The parent TabPanel
29113 * @param {Roo.TabPanelItem} this
29115 "deactivate" : true
29117 this.hidden = false;
29119 Roo.TabPanelItem.superclass.constructor.call(this);
29122 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
29123 purgeListeners : function(){
29124 Roo.util.Observable.prototype.purgeListeners.call(this);
29125 this.el.removeAllListeners();
29128 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
29131 this.pnode.addClass("on");
29134 this.tabPanel.stripWrap.repaint();
29136 this.fireEvent("activate", this.tabPanel, this);
29140 * Returns true if this tab is the active tab.
29141 * @return {Boolean}
29143 isActive : function(){
29144 return this.tabPanel.getActiveTab() == this;
29148 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
29151 this.pnode.removeClass("on");
29153 this.fireEvent("deactivate", this.tabPanel, this);
29156 hideAction : function(){
29157 this.bodyEl.hide();
29158 this.bodyEl.setStyle("position", "absolute");
29159 this.bodyEl.setLeft("-20000px");
29160 this.bodyEl.setTop("-20000px");
29163 showAction : function(){
29164 this.bodyEl.setStyle("position", "relative");
29165 this.bodyEl.setTop("");
29166 this.bodyEl.setLeft("");
29167 this.bodyEl.show();
29171 * Set the tooltip for the tab.
29172 * @param {String} tooltip The tab's tooltip
29174 setTooltip : function(text){
29175 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
29176 this.textEl.dom.qtip = text;
29177 this.textEl.dom.removeAttribute('title');
29179 this.textEl.dom.title = text;
29183 onTabClick : function(e){
29184 e.preventDefault();
29185 this.tabPanel.activate(this.id);
29188 onTabMouseDown : function(e){
29189 e.preventDefault();
29190 this.tabPanel.activate(this.id);
29193 getWidth : function(){
29194 return this.inner.getWidth();
29197 setWidth : function(width){
29198 var iwidth = width - this.pnode.getPadding("lr");
29199 this.inner.setWidth(iwidth);
29200 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
29201 this.pnode.setWidth(width);
29205 * Show or hide the tab
29206 * @param {Boolean} hidden True to hide or false to show.
29208 setHidden : function(hidden){
29209 this.hidden = hidden;
29210 this.pnode.setStyle("display", hidden ? "none" : "");
29214 * Returns true if this tab is "hidden"
29215 * @return {Boolean}
29217 isHidden : function(){
29218 return this.hidden;
29222 * Returns the text for this tab
29225 getText : function(){
29229 autoSize : function(){
29230 //this.el.beginMeasure();
29231 this.textEl.setWidth(1);
29233 * #2804 [new] Tabs in Roojs
29234 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
29236 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
29237 //this.el.endMeasure();
29241 * Sets the text for the tab (Note: this also sets the tooltip text)
29242 * @param {String} text The tab's text and tooltip
29244 setText : function(text){
29246 this.textEl.update(text);
29247 this.setTooltip(text);
29248 if(!this.tabPanel.resizeTabs){
29253 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
29255 activate : function(){
29256 this.tabPanel.activate(this.id);
29260 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
29262 disable : function(){
29263 if(this.tabPanel.active != this){
29264 this.disabled = true;
29265 this.pnode.addClass("disabled");
29270 * Enables this TabPanelItem if it was previously disabled.
29272 enable : function(){
29273 this.disabled = false;
29274 this.pnode.removeClass("disabled");
29278 * Sets the content for this TabPanelItem.
29279 * @param {String} content The content
29280 * @param {Boolean} loadScripts true to look for and load scripts
29282 setContent : function(content, loadScripts){
29283 this.bodyEl.update(content, loadScripts);
29287 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
29288 * @return {Roo.UpdateManager} The UpdateManager
29290 getUpdateManager : function(){
29291 return this.bodyEl.getUpdateManager();
29295 * Set a URL to be used to load the content for this TabPanelItem.
29296 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
29297 * @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)
29298 * @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)
29299 * @return {Roo.UpdateManager} The UpdateManager
29301 setUrl : function(url, params, loadOnce){
29302 if(this.refreshDelegate){
29303 this.un('activate', this.refreshDelegate);
29305 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
29306 this.on("activate", this.refreshDelegate);
29307 return this.bodyEl.getUpdateManager();
29311 _handleRefresh : function(url, params, loadOnce){
29312 if(!loadOnce || !this.loaded){
29313 var updater = this.bodyEl.getUpdateManager();
29314 updater.update(url, params, this._setLoaded.createDelegate(this));
29319 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
29320 * Will fail silently if the setUrl method has not been called.
29321 * This does not activate the panel, just updates its content.
29323 refresh : function(){
29324 if(this.refreshDelegate){
29325 this.loaded = false;
29326 this.refreshDelegate();
29331 _setLoaded : function(){
29332 this.loaded = true;
29336 closeClick : function(e){
29339 this.fireEvent("beforeclose", this, o);
29340 if(o.cancel !== true){
29341 this.tabPanel.removeTab(this.id);
29345 * The text displayed in the tooltip for the close icon.
29348 closeText : "Close this tab"
29352 Roo.TabPanel.prototype.createStrip = function(container){
29353 var strip = document.createElement("div");
29354 strip.className = "x-tabs-wrap";
29355 container.appendChild(strip);
29359 Roo.TabPanel.prototype.createStripList = function(strip){
29360 // div wrapper for retard IE
29361 // returns the "tr" element.
29362 strip.innerHTML = '<div class="x-tabs-strip-wrap">'+
29363 '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
29364 '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
29365 return strip.firstChild.firstChild.firstChild.firstChild;
29368 Roo.TabPanel.prototype.createBody = function(container){
29369 var body = document.createElement("div");
29370 Roo.id(body, "tab-body");
29371 Roo.fly(body).addClass("x-tabs-body");
29372 container.appendChild(body);
29376 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
29377 var body = Roo.getDom(id);
29379 body = document.createElement("div");
29382 Roo.fly(body).addClass("x-tabs-item-body");
29383 bodyEl.insertBefore(body, bodyEl.firstChild);
29387 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
29388 var td = document.createElement("td");
29389 stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
29390 //stripEl.appendChild(td);
29392 td.className = "x-tabs-closable";
29393 if(!this.closeTpl){
29394 this.closeTpl = new Roo.Template(
29395 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
29396 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
29397 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
29400 var el = this.closeTpl.overwrite(td, {"text": text});
29401 var close = el.getElementsByTagName("div")[0];
29402 var inner = el.getElementsByTagName("em")[0];
29403 return {"el": el, "close": close, "inner": inner};
29406 this.tabTpl = new Roo.Template(
29407 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
29408 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
29411 var el = this.tabTpl.overwrite(td, {"text": text});
29412 var inner = el.getElementsByTagName("em")[0];
29413 return {"el": el, "inner": inner};
29417 * Ext JS Library 1.1.1
29418 * Copyright(c) 2006-2007, Ext JS, LLC.
29420 * Originally Released Under LGPL - original licence link has changed is not relivant.
29423 * <script type="text/javascript">
29427 * @class Roo.Button
29428 * @extends Roo.util.Observable
29429 * Simple Button class
29430 * @cfg {String} text The button text
29431 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
29432 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
29433 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
29434 * @cfg {Object} scope The scope of the handler
29435 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
29436 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
29437 * @cfg {Boolean} hidden True to start hidden (defaults to false)
29438 * @cfg {Boolean} disabled True to start disabled (defaults to false)
29439 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
29440 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
29441 applies if enableToggle = true)
29442 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
29443 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
29444 an {@link Roo.util.ClickRepeater} config object (defaults to false).
29446 * Create a new button
29447 * @param {Object} config The config object
29449 Roo.Button = function(renderTo, config)
29453 renderTo = config.renderTo || false;
29456 Roo.apply(this, config);
29460 * Fires when this button is clicked
29461 * @param {Button} this
29462 * @param {EventObject} e The click event
29467 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
29468 * @param {Button} this
29469 * @param {Boolean} pressed
29474 * Fires when the mouse hovers over the button
29475 * @param {Button} this
29476 * @param {Event} e The event object
29478 'mouseover' : true,
29481 * Fires when the mouse exits the button
29482 * @param {Button} this
29483 * @param {Event} e The event object
29488 * Fires when the button is rendered
29489 * @param {Button} this
29494 this.menu = Roo.menu.MenuMgr.get(this.menu);
29496 // register listeners first!! - so render can be captured..
29497 Roo.util.Observable.call(this);
29499 this.render(renderTo);
29505 Roo.extend(Roo.Button, Roo.util.Observable, {
29511 * Read-only. True if this button is hidden
29516 * Read-only. True if this button is disabled
29521 * Read-only. True if this button is pressed (only if enableToggle = true)
29527 * @cfg {Number} tabIndex
29528 * The DOM tabIndex for this button (defaults to undefined)
29530 tabIndex : undefined,
29533 * @cfg {Boolean} enableToggle
29534 * True to enable pressed/not pressed toggling (defaults to false)
29536 enableToggle: false,
29538 * @cfg {Roo.menu.Menu} menu
29539 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
29543 * @cfg {String} menuAlign
29544 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
29546 menuAlign : "tl-bl?",
29549 * @cfg {String} iconCls
29550 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
29552 iconCls : undefined,
29554 * @cfg {String} type
29555 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
29560 menuClassTarget: 'tr',
29563 * @cfg {String} clickEvent
29564 * The type of event to map to the button's event handler (defaults to 'click')
29566 clickEvent : 'click',
29569 * @cfg {Boolean} handleMouseEvents
29570 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
29572 handleMouseEvents : true,
29575 * @cfg {String} tooltipType
29576 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
29578 tooltipType : 'qtip',
29581 * @cfg {String} cls
29582 * A CSS class to apply to the button's main element.
29586 * @cfg {Roo.Template} template (Optional)
29587 * An {@link Roo.Template} with which to create the Button's main element. This Template must
29588 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
29589 * require code modifications if required elements (e.g. a button) aren't present.
29593 render : function(renderTo){
29595 if(this.hideParent){
29596 this.parentEl = Roo.get(renderTo);
29598 if(!this.dhconfig){
29599 if(!this.template){
29600 if(!Roo.Button.buttonTemplate){
29601 // hideous table template
29602 Roo.Button.buttonTemplate = new Roo.Template(
29603 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
29604 '<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>',
29605 "</tr></tbody></table>");
29607 this.template = Roo.Button.buttonTemplate;
29609 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
29610 var btnEl = btn.child("button:first");
29611 btnEl.on('focus', this.onFocus, this);
29612 btnEl.on('blur', this.onBlur, this);
29614 btn.addClass(this.cls);
29617 btnEl.setStyle('background-image', 'url(' +this.icon +')');
29620 btnEl.addClass(this.iconCls);
29622 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
29625 if(this.tabIndex !== undefined){
29626 btnEl.dom.tabIndex = this.tabIndex;
29629 if(typeof this.tooltip == 'object'){
29630 Roo.QuickTips.tips(Roo.apply({
29634 btnEl.dom[this.tooltipType] = this.tooltip;
29638 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
29642 this.el.dom.id = this.el.id = this.id;
29645 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
29646 this.menu.on("show", this.onMenuShow, this);
29647 this.menu.on("hide", this.onMenuHide, this);
29649 btn.addClass("x-btn");
29650 if(Roo.isIE && !Roo.isIE7){
29651 this.autoWidth.defer(1, this);
29655 if(this.handleMouseEvents){
29656 btn.on("mouseover", this.onMouseOver, this);
29657 btn.on("mouseout", this.onMouseOut, this);
29658 btn.on("mousedown", this.onMouseDown, this);
29660 btn.on(this.clickEvent, this.onClick, this);
29661 //btn.on("mouseup", this.onMouseUp, this);
29668 Roo.ButtonToggleMgr.register(this);
29670 this.el.addClass("x-btn-pressed");
29673 var repeater = new Roo.util.ClickRepeater(btn,
29674 typeof this.repeat == "object" ? this.repeat : {}
29676 repeater.on("click", this.onClick, this);
29679 this.fireEvent('render', this);
29683 * Returns the button's underlying element
29684 * @return {Roo.Element} The element
29686 getEl : function(){
29691 * Destroys this Button and removes any listeners.
29693 destroy : function(){
29694 Roo.ButtonToggleMgr.unregister(this);
29695 this.el.removeAllListeners();
29696 this.purgeListeners();
29701 autoWidth : function(){
29703 this.el.setWidth("auto");
29704 if(Roo.isIE7 && Roo.isStrict){
29705 var ib = this.el.child('button');
29706 if(ib && ib.getWidth() > 20){
29708 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
29713 this.el.beginMeasure();
29715 if(this.el.getWidth() < this.minWidth){
29716 this.el.setWidth(this.minWidth);
29719 this.el.endMeasure();
29726 * Assigns this button's click handler
29727 * @param {Function} handler The function to call when the button is clicked
29728 * @param {Object} scope (optional) Scope for the function passed in
29730 setHandler : function(handler, scope){
29731 this.handler = handler;
29732 this.scope = scope;
29736 * Sets this button's text
29737 * @param {String} text The button text
29739 setText : function(text){
29742 this.el.child("td.x-btn-center button.x-btn-text").update(text);
29748 * Gets the text for this button
29749 * @return {String} The button text
29751 getText : function(){
29759 this.hidden = false;
29761 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
29769 this.hidden = true;
29771 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
29776 * Convenience function for boolean show/hide
29777 * @param {Boolean} visible True to show, false to hide
29779 setVisible: function(visible){
29788 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
29789 * @param {Boolean} state (optional) Force a particular state
29791 toggle : function(state){
29792 state = state === undefined ? !this.pressed : state;
29793 if(state != this.pressed){
29795 this.el.addClass("x-btn-pressed");
29796 this.pressed = true;
29797 this.fireEvent("toggle", this, true);
29799 this.el.removeClass("x-btn-pressed");
29800 this.pressed = false;
29801 this.fireEvent("toggle", this, false);
29803 if(this.toggleHandler){
29804 this.toggleHandler.call(this.scope || this, this, state);
29812 focus : function(){
29813 this.el.child('button:first').focus();
29817 * Disable this button
29819 disable : function(){
29821 this.el.addClass("x-btn-disabled");
29823 this.disabled = true;
29827 * Enable this button
29829 enable : function(){
29831 this.el.removeClass("x-btn-disabled");
29833 this.disabled = false;
29837 * Convenience function for boolean enable/disable
29838 * @param {Boolean} enabled True to enable, false to disable
29840 setDisabled : function(v){
29841 this[v !== true ? "enable" : "disable"]();
29845 onClick : function(e)
29848 e.preventDefault();
29853 if(!this.disabled){
29854 if(this.enableToggle){
29857 if(this.menu && !this.menu.isVisible()){
29858 this.menu.show(this.el, this.menuAlign);
29860 this.fireEvent("click", this, e);
29862 this.el.removeClass("x-btn-over");
29863 this.handler.call(this.scope || this, this, e);
29868 onMouseOver : function(e){
29869 if(!this.disabled){
29870 this.el.addClass("x-btn-over");
29871 this.fireEvent('mouseover', this, e);
29875 onMouseOut : function(e){
29876 if(!e.within(this.el, true)){
29877 this.el.removeClass("x-btn-over");
29878 this.fireEvent('mouseout', this, e);
29882 onFocus : function(e){
29883 if(!this.disabled){
29884 this.el.addClass("x-btn-focus");
29888 onBlur : function(e){
29889 this.el.removeClass("x-btn-focus");
29892 onMouseDown : function(e){
29893 if(!this.disabled && e.button == 0){
29894 this.el.addClass("x-btn-click");
29895 Roo.get(document).on('mouseup', this.onMouseUp, this);
29899 onMouseUp : function(e){
29901 this.el.removeClass("x-btn-click");
29902 Roo.get(document).un('mouseup', this.onMouseUp, this);
29906 onMenuShow : function(e){
29907 this.el.addClass("x-btn-menu-active");
29910 onMenuHide : function(e){
29911 this.el.removeClass("x-btn-menu-active");
29915 // Private utility class used by Button
29916 Roo.ButtonToggleMgr = function(){
29919 function toggleGroup(btn, state){
29921 var g = groups[btn.toggleGroup];
29922 for(var i = 0, l = g.length; i < l; i++){
29924 g[i].toggle(false);
29931 register : function(btn){
29932 if(!btn.toggleGroup){
29935 var g = groups[btn.toggleGroup];
29937 g = groups[btn.toggleGroup] = [];
29940 btn.on("toggle", toggleGroup);
29943 unregister : function(btn){
29944 if(!btn.toggleGroup){
29947 var g = groups[btn.toggleGroup];
29950 btn.un("toggle", toggleGroup);
29956 * Ext JS Library 1.1.1
29957 * Copyright(c) 2006-2007, Ext JS, LLC.
29959 * Originally Released Under LGPL - original licence link has changed is not relivant.
29962 * <script type="text/javascript">
29966 * @class Roo.SplitButton
29967 * @extends Roo.Button
29968 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
29969 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
29970 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
29971 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
29972 * @cfg {String} arrowTooltip The title attribute of the arrow
29974 * Create a new menu button
29975 * @param {String/HTMLElement/Element} renderTo The element to append the button to
29976 * @param {Object} config The config object
29978 Roo.SplitButton = function(renderTo, config){
29979 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
29981 * @event arrowclick
29982 * Fires when this button's arrow is clicked
29983 * @param {SplitButton} this
29984 * @param {EventObject} e The click event
29986 this.addEvents({"arrowclick":true});
29989 Roo.extend(Roo.SplitButton, Roo.Button, {
29990 render : function(renderTo){
29991 // this is one sweet looking template!
29992 var tpl = new Roo.Template(
29993 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
29994 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
29995 '<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>',
29996 "</tbody></table></td><td>",
29997 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
29998 '<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>',
29999 "</tbody></table></td></tr></table>"
30001 var btn = tpl.append(renderTo, [this.text, this.type], true);
30002 var btnEl = btn.child("button");
30004 btn.addClass(this.cls);
30007 btnEl.setStyle('background-image', 'url(' +this.icon +')');
30010 btnEl.addClass(this.iconCls);
30012 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
30016 if(this.handleMouseEvents){
30017 btn.on("mouseover", this.onMouseOver, this);
30018 btn.on("mouseout", this.onMouseOut, this);
30019 btn.on("mousedown", this.onMouseDown, this);
30020 btn.on("mouseup", this.onMouseUp, this);
30022 btn.on(this.clickEvent, this.onClick, this);
30024 if(typeof this.tooltip == 'object'){
30025 Roo.QuickTips.tips(Roo.apply({
30029 btnEl.dom[this.tooltipType] = this.tooltip;
30032 if(this.arrowTooltip){
30033 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
30042 this.el.addClass("x-btn-pressed");
30044 if(Roo.isIE && !Roo.isIE7){
30045 this.autoWidth.defer(1, this);
30050 this.menu.on("show", this.onMenuShow, this);
30051 this.menu.on("hide", this.onMenuHide, this);
30053 this.fireEvent('render', this);
30057 autoWidth : function(){
30059 var tbl = this.el.child("table:first");
30060 var tbl2 = this.el.child("table:last");
30061 this.el.setWidth("auto");
30062 tbl.setWidth("auto");
30063 if(Roo.isIE7 && Roo.isStrict){
30064 var ib = this.el.child('button:first');
30065 if(ib && ib.getWidth() > 20){
30067 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
30072 this.el.beginMeasure();
30074 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
30075 tbl.setWidth(this.minWidth-tbl2.getWidth());
30078 this.el.endMeasure();
30081 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
30085 * Sets this button's click handler
30086 * @param {Function} handler The function to call when the button is clicked
30087 * @param {Object} scope (optional) Scope for the function passed above
30089 setHandler : function(handler, scope){
30090 this.handler = handler;
30091 this.scope = scope;
30095 * Sets this button's arrow click handler
30096 * @param {Function} handler The function to call when the arrow is clicked
30097 * @param {Object} scope (optional) Scope for the function passed above
30099 setArrowHandler : function(handler, scope){
30100 this.arrowHandler = handler;
30101 this.scope = scope;
30107 focus : function(){
30109 this.el.child("button:first").focus();
30114 onClick : function(e){
30115 e.preventDefault();
30116 if(!this.disabled){
30117 if(e.getTarget(".x-btn-menu-arrow-wrap")){
30118 if(this.menu && !this.menu.isVisible()){
30119 this.menu.show(this.el, this.menuAlign);
30121 this.fireEvent("arrowclick", this, e);
30122 if(this.arrowHandler){
30123 this.arrowHandler.call(this.scope || this, this, e);
30126 this.fireEvent("click", this, e);
30128 this.handler.call(this.scope || this, this, e);
30134 onMouseDown : function(e){
30135 if(!this.disabled){
30136 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
30140 onMouseUp : function(e){
30141 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
30146 // backwards compat
30147 Roo.MenuButton = Roo.SplitButton;/*
30149 * Ext JS Library 1.1.1
30150 * Copyright(c) 2006-2007, Ext JS, LLC.
30152 * Originally Released Under LGPL - original licence link has changed is not relivant.
30155 * <script type="text/javascript">
30159 * @class Roo.Toolbar
30160 * @children Roo.Toolbar.Item Roo.form.Field
30161 * Basic Toolbar class.
30163 * Creates a new Toolbar
30164 * @param {Object} container The config object
30166 Roo.Toolbar = function(container, buttons, config)
30168 /// old consturctor format still supported..
30169 if(container instanceof Array){ // omit the container for later rendering
30170 buttons = container;
30174 if (typeof(container) == 'object' && container.xtype) {
30175 config = container;
30176 container = config.container;
30177 buttons = config.buttons || []; // not really - use items!!
30180 if (config && config.items) {
30181 xitems = config.items;
30182 delete config.items;
30184 Roo.apply(this, config);
30185 this.buttons = buttons;
30188 this.render(container);
30190 this.xitems = xitems;
30191 Roo.each(xitems, function(b) {
30197 Roo.Toolbar.prototype = {
30199 * @cfg {Array} items
30200 * array of button configs or elements to add (will be converted to a MixedCollection)
30204 * @cfg {String/HTMLElement/Element} container
30205 * The id or element that will contain the toolbar
30208 render : function(ct){
30209 this.el = Roo.get(ct);
30211 this.el.addClass(this.cls);
30213 // using a table allows for vertical alignment
30214 // 100% width is needed by Safari...
30215 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
30216 this.tr = this.el.child("tr", true);
30218 this.items = new Roo.util.MixedCollection(false, function(o){
30219 return o.id || ("item" + (++autoId));
30222 this.add.apply(this, this.buttons);
30223 delete this.buttons;
30228 * Adds element(s) to the toolbar -- this function takes a variable number of
30229 * arguments of mixed type and adds them to the toolbar.
30230 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
30232 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
30233 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
30234 * <li>Field: Any form field (equivalent to {@link #addField})</li>
30235 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
30236 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
30237 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
30238 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
30239 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
30240 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
30242 * @param {Mixed} arg2
30243 * @param {Mixed} etc.
30246 var a = arguments, l = a.length;
30247 for(var i = 0; i < l; i++){
30252 _add : function(el) {
30255 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
30258 if (el.applyTo){ // some kind of form field
30259 return this.addField(el);
30261 if (el.render){ // some kind of Toolbar.Item
30262 return this.addItem(el);
30264 if (typeof el == "string"){ // string
30265 if(el == "separator" || el == "-"){
30266 return this.addSeparator();
30269 return this.addSpacer();
30272 return this.addFill();
30274 return this.addText(el);
30277 if(el.tagName){ // element
30278 return this.addElement(el);
30280 if(typeof el == "object"){ // must be button config?
30281 return this.addButton(el);
30283 // and now what?!?!
30289 * Add an Xtype element
30290 * @param {Object} xtype Xtype Object
30291 * @return {Object} created Object
30293 addxtype : function(e){
30294 return this.add(e);
30298 * Returns the Element for this toolbar.
30299 * @return {Roo.Element}
30301 getEl : function(){
30307 * @return {Roo.Toolbar.Item} The separator item
30309 addSeparator : function(){
30310 return this.addItem(new Roo.Toolbar.Separator());
30314 * Adds a spacer element
30315 * @return {Roo.Toolbar.Spacer} The spacer item
30317 addSpacer : function(){
30318 return this.addItem(new Roo.Toolbar.Spacer());
30322 * Adds a fill element that forces subsequent additions to the right side of the toolbar
30323 * @return {Roo.Toolbar.Fill} The fill item
30325 addFill : function(){
30326 return this.addItem(new Roo.Toolbar.Fill());
30330 * Adds any standard HTML element to the toolbar
30331 * @param {String/HTMLElement/Element} el The element or id of the element to add
30332 * @return {Roo.Toolbar.Item} The element's item
30334 addElement : function(el){
30335 return this.addItem(new Roo.Toolbar.Item(el));
30338 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
30339 * @type Roo.util.MixedCollection
30344 * Adds any Toolbar.Item or subclass
30345 * @param {Roo.Toolbar.Item} item
30346 * @return {Roo.Toolbar.Item} The item
30348 addItem : function(item){
30349 var td = this.nextBlock();
30351 this.items.add(item);
30356 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
30357 * @param {Object/Array} config A button config or array of configs
30358 * @return {Roo.Toolbar.Button/Array}
30360 addButton : function(config){
30361 if(config instanceof Array){
30363 for(var i = 0, len = config.length; i < len; i++) {
30364 buttons.push(this.addButton(config[i]));
30369 if(!(config instanceof Roo.Toolbar.Button)){
30371 new Roo.Toolbar.SplitButton(config) :
30372 new Roo.Toolbar.Button(config);
30374 var td = this.nextBlock();
30381 * Adds text to the toolbar
30382 * @param {String} text The text to add
30383 * @return {Roo.Toolbar.Item} The element's item
30385 addText : function(text){
30386 return this.addItem(new Roo.Toolbar.TextItem(text));
30390 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
30391 * @param {Number} index The index where the item is to be inserted
30392 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
30393 * @return {Roo.Toolbar.Button/Item}
30395 insertButton : function(index, item){
30396 if(item instanceof Array){
30398 for(var i = 0, len = item.length; i < len; i++) {
30399 buttons.push(this.insertButton(index + i, item[i]));
30403 if (!(item instanceof Roo.Toolbar.Button)){
30404 item = new Roo.Toolbar.Button(item);
30406 var td = document.createElement("td");
30407 this.tr.insertBefore(td, this.tr.childNodes[index]);
30409 this.items.insert(index, item);
30414 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
30415 * @param {Object} config
30416 * @return {Roo.Toolbar.Item} The element's item
30418 addDom : function(config, returnEl){
30419 var td = this.nextBlock();
30420 Roo.DomHelper.overwrite(td, config);
30421 var ti = new Roo.Toolbar.Item(td.firstChild);
30423 this.items.add(ti);
30428 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
30429 * @type Roo.util.MixedCollection
30434 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc).
30435 * Note: the field should not have been rendered yet. For a field that has already been
30436 * rendered, use {@link #addElement}.
30437 * @param {Roo.form.Field} field
30438 * @return {Roo.ToolbarItem}
30442 addField : function(field) {
30443 if (!this.fields) {
30445 this.fields = new Roo.util.MixedCollection(false, function(o){
30446 return o.id || ("item" + (++autoId));
30451 var td = this.nextBlock();
30453 var ti = new Roo.Toolbar.Item(td.firstChild);
30455 this.items.add(ti);
30456 this.fields.add(field);
30467 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
30468 this.el.child('div').hide();
30476 this.el.child('div').show();
30480 nextBlock : function(){
30481 var td = document.createElement("td");
30482 this.tr.appendChild(td);
30487 destroy : function(){
30488 if(this.items){ // rendered?
30489 Roo.destroy.apply(Roo, this.items.items);
30491 if(this.fields){ // rendered?
30492 Roo.destroy.apply(Roo, this.fields.items);
30494 Roo.Element.uncache(this.el, this.tr);
30499 * @class Roo.Toolbar.Item
30500 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
30502 * Creates a new Item
30503 * @param {HTMLElement} el
30505 Roo.Toolbar.Item = function(el){
30507 if (typeof (el.xtype) != 'undefined') {
30512 this.el = Roo.getDom(el);
30513 this.id = Roo.id(this.el);
30514 this.hidden = false;
30519 * Fires when the button is rendered
30520 * @param {Button} this
30524 Roo.Toolbar.Item.superclass.constructor.call(this,cfg);
30526 Roo.extend(Roo.Toolbar.Item, Roo.util.Observable, {
30527 //Roo.Toolbar.Item.prototype = {
30530 * Get this item's HTML Element
30531 * @return {HTMLElement}
30533 getEl : function(){
30538 render : function(td){
30541 td.appendChild(this.el);
30543 this.fireEvent('render', this);
30547 * Removes and destroys this item.
30549 destroy : function(){
30550 this.td.parentNode.removeChild(this.td);
30557 this.hidden = false;
30558 this.td.style.display = "";
30565 this.hidden = true;
30566 this.td.style.display = "none";
30570 * Convenience function for boolean show/hide.
30571 * @param {Boolean} visible true to show/false to hide
30573 setVisible: function(visible){
30582 * Try to focus this item.
30584 focus : function(){
30585 Roo.fly(this.el).focus();
30589 * Disables this item.
30591 disable : function(){
30592 Roo.fly(this.td).addClass("x-item-disabled");
30593 this.disabled = true;
30594 this.el.disabled = true;
30598 * Enables this item.
30600 enable : function(){
30601 Roo.fly(this.td).removeClass("x-item-disabled");
30602 this.disabled = false;
30603 this.el.disabled = false;
30609 * @class Roo.Toolbar.Separator
30610 * @extends Roo.Toolbar.Item
30611 * A simple toolbar separator class
30613 * Creates a new Separator
30615 Roo.Toolbar.Separator = function(cfg){
30617 var s = document.createElement("span");
30618 s.className = "ytb-sep";
30623 Roo.Toolbar.Separator.superclass.constructor.call(this, cfg || s);
30625 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
30626 enable:Roo.emptyFn,
30627 disable:Roo.emptyFn,
30632 * @class Roo.Toolbar.Spacer
30633 * @extends Roo.Toolbar.Item
30634 * A simple element that adds extra horizontal space to a toolbar.
30636 * Creates a new Spacer
30638 Roo.Toolbar.Spacer = function(cfg){
30639 var s = document.createElement("div");
30640 s.className = "ytb-spacer";
30644 Roo.Toolbar.Spacer.superclass.constructor.call(this, cfg || s);
30646 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
30647 enable:Roo.emptyFn,
30648 disable:Roo.emptyFn,
30653 * @class Roo.Toolbar.Fill
30654 * @extends Roo.Toolbar.Spacer
30655 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
30657 * Creates a new Spacer
30659 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
30661 render : function(td){
30662 td.style.width = '100%';
30663 Roo.Toolbar.Fill.superclass.render.call(this, td);
30668 * @class Roo.Toolbar.TextItem
30669 * @extends Roo.Toolbar.Item
30670 * A simple class that renders text directly into a toolbar.
30672 * Creates a new TextItem
30673 * @cfg {string} text
30675 Roo.Toolbar.TextItem = function(cfg){
30676 var text = cfg || "";
30677 if (typeof(cfg) == 'object') {
30678 text = cfg.text || "";
30682 var s = document.createElement("span");
30683 s.className = "ytb-text";
30684 s.innerHTML = text;
30689 Roo.Toolbar.TextItem.superclass.constructor.call(this, cfg || s);
30691 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
30694 enable:Roo.emptyFn,
30695 disable:Roo.emptyFn,
30700 * @class Roo.Toolbar.Button
30701 * @extends Roo.Button
30702 * A button that renders into a toolbar.
30704 * Creates a new Button
30705 * @param {Object} config A standard {@link Roo.Button} config object
30707 Roo.Toolbar.Button = function(config){
30708 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
30710 Roo.extend(Roo.Toolbar.Button, Roo.Button,
30714 render : function(td){
30716 Roo.Toolbar.Button.superclass.render.call(this, td);
30720 * Removes and destroys this button
30722 destroy : function(){
30723 Roo.Toolbar.Button.superclass.destroy.call(this);
30724 this.td.parentNode.removeChild(this.td);
30728 * Shows this button
30731 this.hidden = false;
30732 this.td.style.display = "";
30736 * Hides this button
30739 this.hidden = true;
30740 this.td.style.display = "none";
30744 * Disables this item
30746 disable : function(){
30747 Roo.fly(this.td).addClass("x-item-disabled");
30748 this.disabled = true;
30752 * Enables this item
30754 enable : function(){
30755 Roo.fly(this.td).removeClass("x-item-disabled");
30756 this.disabled = false;
30759 // backwards compat
30760 Roo.ToolbarButton = Roo.Toolbar.Button;
30763 * @class Roo.Toolbar.SplitButton
30764 * @extends Roo.SplitButton
30765 * A menu button that renders into a toolbar.
30767 * Creates a new SplitButton
30768 * @param {Object} config A standard {@link Roo.SplitButton} config object
30770 Roo.Toolbar.SplitButton = function(config){
30771 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
30773 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
30774 render : function(td){
30776 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
30780 * Removes and destroys this button
30782 destroy : function(){
30783 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
30784 this.td.parentNode.removeChild(this.td);
30788 * Shows this button
30791 this.hidden = false;
30792 this.td.style.display = "";
30796 * Hides this button
30799 this.hidden = true;
30800 this.td.style.display = "none";
30804 // backwards compat
30805 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
30807 * Ext JS Library 1.1.1
30808 * Copyright(c) 2006-2007, Ext JS, LLC.
30810 * Originally Released Under LGPL - original licence link has changed is not relivant.
30813 * <script type="text/javascript">
30817 * @class Roo.PagingToolbar
30818 * @extends Roo.Toolbar
30819 * @children Roo.Toolbar.Item Roo.form.Field
30820 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
30822 * Create a new PagingToolbar
30823 * @param {Object} config The config object
30825 Roo.PagingToolbar = function(el, ds, config)
30827 // old args format still supported... - xtype is prefered..
30828 if (typeof(el) == 'object' && el.xtype) {
30829 // created from xtype...
30831 ds = el.dataSource;
30832 el = config.container;
30835 if (config.items) {
30836 items = config.items;
30840 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
30843 this.renderButtons(this.el);
30846 // supprot items array.
30848 Roo.each(items, function(e) {
30849 this.add(Roo.factory(e));
30854 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
30856 * @cfg {Roo.data.Store} dataSource
30857 * The underlying data store providing the paged data
30860 * @cfg {String/HTMLElement/Element} container
30861 * container The id or element that will contain the toolbar
30864 * @cfg {Boolean} displayInfo
30865 * True to display the displayMsg (defaults to false)
30868 * @cfg {Number} pageSize
30869 * The number of records to display per page (defaults to 20)
30873 * @cfg {String} displayMsg
30874 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
30876 displayMsg : 'Displaying {0} - {1} of {2}',
30878 * @cfg {String} emptyMsg
30879 * The message to display when no records are found (defaults to "No data to display")
30881 emptyMsg : 'No data to display',
30883 * Customizable piece of the default paging text (defaults to "Page")
30886 beforePageText : "Page",
30888 * Customizable piece of the default paging text (defaults to "of %0")
30891 afterPageText : "of {0}",
30893 * Customizable piece of the default paging text (defaults to "First Page")
30896 firstText : "First Page",
30898 * Customizable piece of the default paging text (defaults to "Previous Page")
30901 prevText : "Previous Page",
30903 * Customizable piece of the default paging text (defaults to "Next Page")
30906 nextText : "Next Page",
30908 * Customizable piece of the default paging text (defaults to "Last Page")
30911 lastText : "Last Page",
30913 * Customizable piece of the default paging text (defaults to "Refresh")
30916 refreshText : "Refresh",
30919 renderButtons : function(el){
30920 Roo.PagingToolbar.superclass.render.call(this, el);
30921 this.first = this.addButton({
30922 tooltip: this.firstText,
30923 cls: "x-btn-icon x-grid-page-first",
30925 handler: this.onClick.createDelegate(this, ["first"])
30927 this.prev = this.addButton({
30928 tooltip: this.prevText,
30929 cls: "x-btn-icon x-grid-page-prev",
30931 handler: this.onClick.createDelegate(this, ["prev"])
30933 //this.addSeparator();
30934 this.add(this.beforePageText);
30935 this.field = Roo.get(this.addDom({
30940 cls: "x-grid-page-number"
30942 this.field.on("keydown", this.onPagingKeydown, this);
30943 this.field.on("focus", function(){this.dom.select();});
30944 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
30945 this.field.setHeight(18);
30946 //this.addSeparator();
30947 this.next = this.addButton({
30948 tooltip: this.nextText,
30949 cls: "x-btn-icon x-grid-page-next",
30951 handler: this.onClick.createDelegate(this, ["next"])
30953 this.last = this.addButton({
30954 tooltip: this.lastText,
30955 cls: "x-btn-icon x-grid-page-last",
30957 handler: this.onClick.createDelegate(this, ["last"])
30959 //this.addSeparator();
30960 this.loading = this.addButton({
30961 tooltip: this.refreshText,
30962 cls: "x-btn-icon x-grid-loading",
30963 handler: this.onClick.createDelegate(this, ["refresh"])
30966 if(this.displayInfo){
30967 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
30972 updateInfo : function(){
30973 if(this.displayEl){
30974 var count = this.ds.getCount();
30975 var msg = count == 0 ?
30979 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
30981 this.displayEl.update(msg);
30986 onLoad : function(ds, r, o){
30987 this.cursor = o.params ? o.params.start : 0;
30988 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
30990 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
30991 this.field.dom.value = ap;
30992 this.first.setDisabled(ap == 1);
30993 this.prev.setDisabled(ap == 1);
30994 this.next.setDisabled(ap == ps);
30995 this.last.setDisabled(ap == ps);
30996 this.loading.enable();
31001 getPageData : function(){
31002 var total = this.ds.getTotalCount();
31005 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
31006 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
31011 onLoadError : function(){
31012 this.loading.enable();
31016 onPagingKeydown : function(e){
31017 var k = e.getKey();
31018 var d = this.getPageData();
31020 var v = this.field.dom.value, pageNum;
31021 if(!v || isNaN(pageNum = parseInt(v, 10))){
31022 this.field.dom.value = d.activePage;
31025 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
31026 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
31029 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))
31031 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
31032 this.field.dom.value = pageNum;
31033 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
31036 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
31038 var v = this.field.dom.value, pageNum;
31039 var increment = (e.shiftKey) ? 10 : 1;
31040 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
31043 if(!v || isNaN(pageNum = parseInt(v, 10))) {
31044 this.field.dom.value = d.activePage;
31047 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
31049 this.field.dom.value = parseInt(v, 10) + increment;
31050 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
31051 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
31058 beforeLoad : function(){
31060 this.loading.disable();
31065 onClick : function(which){
31069 ds.load({params:{start: 0, limit: this.pageSize}});
31072 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
31075 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
31078 var total = ds.getTotalCount();
31079 var extra = total % this.pageSize;
31080 var lastStart = extra ? (total - extra) : total-this.pageSize;
31081 ds.load({params:{start: lastStart, limit: this.pageSize}});
31084 ds.load({params:{start: this.cursor, limit: this.pageSize}});
31090 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
31091 * @param {Roo.data.Store} store The data store to unbind
31093 unbind : function(ds){
31094 ds.un("beforeload", this.beforeLoad, this);
31095 ds.un("load", this.onLoad, this);
31096 ds.un("loadexception", this.onLoadError, this);
31097 ds.un("remove", this.updateInfo, this);
31098 ds.un("add", this.updateInfo, this);
31099 this.ds = undefined;
31103 * Binds the paging toolbar to the specified {@link Roo.data.Store}
31104 * @param {Roo.data.Store} store The data store to bind
31106 bind : function(ds){
31107 ds.on("beforeload", this.beforeLoad, this);
31108 ds.on("load", this.onLoad, this);
31109 ds.on("loadexception", this.onLoadError, this);
31110 ds.on("remove", this.updateInfo, this);
31111 ds.on("add", this.updateInfo, this);
31116 * Ext JS Library 1.1.1
31117 * Copyright(c) 2006-2007, Ext JS, LLC.
31119 * Originally Released Under LGPL - original licence link has changed is not relivant.
31122 * <script type="text/javascript">
31126 * @class Roo.Resizable
31127 * @extends Roo.util.Observable
31128 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
31129 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
31130 * 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
31131 * the element will be wrapped for you automatically.</p>
31132 * <p>Here is the list of valid resize handles:</p>
31135 ------ -------------------
31144 'hd' horizontal drag
31147 * <p>Here's an example showing the creation of a typical Resizable:</p>
31149 var resizer = new Roo.Resizable("element-id", {
31157 resizer.on("resize", myHandler);
31159 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
31160 * resizer.east.setDisplayed(false);</p>
31161 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
31162 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
31163 * resize operation's new size (defaults to [0, 0])
31164 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
31165 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
31166 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
31167 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
31168 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
31169 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
31170 * @cfg {Number} width The width of the element in pixels (defaults to null)
31171 * @cfg {Number} height The height of the element in pixels (defaults to null)
31172 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
31173 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
31174 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
31175 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
31176 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
31177 * in favor of the handles config option (defaults to false)
31178 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
31179 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
31180 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
31181 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
31182 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
31183 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
31184 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
31185 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
31186 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
31187 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
31188 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
31190 * Create a new resizable component
31191 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
31192 * @param {Object} config configuration options
31194 Roo.Resizable = function(el, config)
31196 this.el = Roo.get(el);
31198 if(config && config.wrap){
31199 config.resizeChild = this.el;
31200 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
31201 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
31202 this.el.setStyle("overflow", "hidden");
31203 this.el.setPositioning(config.resizeChild.getPositioning());
31204 config.resizeChild.clearPositioning();
31205 if(!config.width || !config.height){
31206 var csize = config.resizeChild.getSize();
31207 this.el.setSize(csize.width, csize.height);
31209 if(config.pinned && !config.adjustments){
31210 config.adjustments = "auto";
31214 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
31215 this.proxy.unselectable();
31216 this.proxy.enableDisplayMode('block');
31218 Roo.apply(this, config);
31221 this.disableTrackOver = true;
31222 this.el.addClass("x-resizable-pinned");
31224 // if the element isn't positioned, make it relative
31225 var position = this.el.getStyle("position");
31226 if(position != "absolute" && position != "fixed"){
31227 this.el.setStyle("position", "relative");
31229 if(!this.handles){ // no handles passed, must be legacy style
31230 this.handles = 's,e,se';
31231 if(this.multiDirectional){
31232 this.handles += ',n,w';
31235 if(this.handles == "all"){
31236 this.handles = "n s e w ne nw se sw";
31238 var hs = this.handles.split(/\s*?[,;]\s*?| /);
31239 var ps = Roo.Resizable.positions;
31240 for(var i = 0, len = hs.length; i < len; i++){
31241 if(hs[i] && ps[hs[i]]){
31242 var pos = ps[hs[i]];
31243 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
31247 this.corner = this.southeast;
31249 // updateBox = the box can move..
31250 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
31251 this.updateBox = true;
31254 this.activeHandle = null;
31256 if(this.resizeChild){
31257 if(typeof this.resizeChild == "boolean"){
31258 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
31260 this.resizeChild = Roo.get(this.resizeChild, true);
31264 if(this.adjustments == "auto"){
31265 var rc = this.resizeChild;
31266 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
31267 if(rc && (hw || hn)){
31268 rc.position("relative");
31269 rc.setLeft(hw ? hw.el.getWidth() : 0);
31270 rc.setTop(hn ? hn.el.getHeight() : 0);
31272 this.adjustments = [
31273 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
31274 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
31278 if(this.draggable){
31279 this.dd = this.dynamic ?
31280 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
31281 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
31287 * @event beforeresize
31288 * Fired before resize is allowed. Set enabled to false to cancel resize.
31289 * @param {Roo.Resizable} this
31290 * @param {Roo.EventObject} e The mousedown event
31292 "beforeresize" : true,
31295 * Fired a resizing.
31296 * @param {Roo.Resizable} this
31297 * @param {Number} x The new x position
31298 * @param {Number} y The new y position
31299 * @param {Number} w The new w width
31300 * @param {Number} h The new h hight
31301 * @param {Roo.EventObject} e The mouseup event
31306 * Fired after a resize.
31307 * @param {Roo.Resizable} this
31308 * @param {Number} width The new width
31309 * @param {Number} height The new height
31310 * @param {Roo.EventObject} e The mouseup event
31315 if(this.width !== null && this.height !== null){
31316 this.resizeTo(this.width, this.height);
31318 this.updateChildSize();
31321 this.el.dom.style.zoom = 1;
31323 Roo.Resizable.superclass.constructor.call(this);
31326 Roo.extend(Roo.Resizable, Roo.util.Observable, {
31327 resizeChild : false,
31328 adjustments : [0, 0],
31338 multiDirectional : false,
31339 disableTrackOver : false,
31340 easing : 'easeOutStrong',
31341 widthIncrement : 0,
31342 heightIncrement : 0,
31346 preserveRatio : false,
31347 transparent: false,
31353 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
31355 constrainTo: undefined,
31357 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
31359 resizeRegion: undefined,
31363 * Perform a manual resize
31364 * @param {Number} width
31365 * @param {Number} height
31367 resizeTo : function(width, height){
31368 this.el.setSize(width, height);
31369 this.updateChildSize();
31370 this.fireEvent("resize", this, width, height, null);
31374 startSizing : function(e, handle){
31375 this.fireEvent("beforeresize", this, e);
31376 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
31379 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
31380 this.overlay.unselectable();
31381 this.overlay.enableDisplayMode("block");
31382 this.overlay.on("mousemove", this.onMouseMove, this);
31383 this.overlay.on("mouseup", this.onMouseUp, this);
31385 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
31387 this.resizing = true;
31388 this.startBox = this.el.getBox();
31389 this.startPoint = e.getXY();
31390 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
31391 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
31393 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
31394 this.overlay.show();
31396 if(this.constrainTo) {
31397 var ct = Roo.get(this.constrainTo);
31398 this.resizeRegion = ct.getRegion().adjust(
31399 ct.getFrameWidth('t'),
31400 ct.getFrameWidth('l'),
31401 -ct.getFrameWidth('b'),
31402 -ct.getFrameWidth('r')
31406 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
31408 this.proxy.setBox(this.startBox);
31410 this.proxy.setStyle('visibility', 'visible');
31416 onMouseDown : function(handle, e){
31419 this.activeHandle = handle;
31420 this.startSizing(e, handle);
31425 onMouseUp : function(e){
31426 var size = this.resizeElement();
31427 this.resizing = false;
31429 this.overlay.hide();
31431 this.fireEvent("resize", this, size.width, size.height, e);
31435 updateChildSize : function(){
31437 if(this.resizeChild){
31439 var child = this.resizeChild;
31440 var adj = this.adjustments;
31441 if(el.dom.offsetWidth){
31442 var b = el.getSize(true);
31443 child.setSize(b.width+adj[0], b.height+adj[1]);
31445 // Second call here for IE
31446 // The first call enables instant resizing and
31447 // the second call corrects scroll bars if they
31450 setTimeout(function(){
31451 if(el.dom.offsetWidth){
31452 var b = el.getSize(true);
31453 child.setSize(b.width+adj[0], b.height+adj[1]);
31461 snap : function(value, inc, min){
31462 if(!inc || !value) {
31465 var newValue = value;
31466 var m = value % inc;
31469 newValue = value + (inc-m);
31471 newValue = value - m;
31474 return Math.max(min, newValue);
31478 resizeElement : function(){
31479 var box = this.proxy.getBox();
31480 if(this.updateBox){
31481 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
31483 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
31485 this.updateChildSize();
31493 constrain : function(v, diff, m, mx){
31496 }else if(v - diff > mx){
31503 onMouseMove : function(e){
31506 try{// try catch so if something goes wrong the user doesn't get hung
31508 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
31512 //var curXY = this.startPoint;
31513 var curSize = this.curSize || this.startBox;
31514 var x = this.startBox.x, y = this.startBox.y;
31515 var ox = x, oy = y;
31516 var w = curSize.width, h = curSize.height;
31517 var ow = w, oh = h;
31518 var mw = this.minWidth, mh = this.minHeight;
31519 var mxw = this.maxWidth, mxh = this.maxHeight;
31520 var wi = this.widthIncrement;
31521 var hi = this.heightIncrement;
31523 var eventXY = e.getXY();
31524 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
31525 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
31527 var pos = this.activeHandle.position;
31532 w = Math.min(Math.max(mw, w), mxw);
31537 h = Math.min(Math.max(mh, h), mxh);
31542 w = Math.min(Math.max(mw, w), mxw);
31543 h = Math.min(Math.max(mh, h), mxh);
31546 diffY = this.constrain(h, diffY, mh, mxh);
31553 var adiffX = Math.abs(diffX);
31554 var sub = (adiffX % wi); // how much
31555 if (sub > (wi/2)) { // far enough to snap
31556 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
31558 // remove difference..
31559 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
31563 x = Math.max(this.minX, x);
31566 diffX = this.constrain(w, diffX, mw, mxw);
31572 w = Math.min(Math.max(mw, w), mxw);
31573 diffY = this.constrain(h, diffY, mh, mxh);
31578 diffX = this.constrain(w, diffX, mw, mxw);
31579 diffY = this.constrain(h, diffY, mh, mxh);
31586 diffX = this.constrain(w, diffX, mw, mxw);
31588 h = Math.min(Math.max(mh, h), mxh);
31594 var sw = this.snap(w, wi, mw);
31595 var sh = this.snap(h, hi, mh);
31596 if(sw != w || sh != h){
31619 if(this.preserveRatio){
31624 h = Math.min(Math.max(mh, h), mxh);
31629 w = Math.min(Math.max(mw, w), mxw);
31634 w = Math.min(Math.max(mw, w), mxw);
31640 w = Math.min(Math.max(mw, w), mxw);
31646 h = Math.min(Math.max(mh, h), mxh);
31654 h = Math.min(Math.max(mh, h), mxh);
31664 h = Math.min(Math.max(mh, h), mxh);
31672 if (pos == 'hdrag') {
31675 this.proxy.setBounds(x, y, w, h);
31677 this.resizeElement();
31681 this.fireEvent("resizing", this, x, y, w, h, e);
31685 handleOver : function(){
31687 this.el.addClass("x-resizable-over");
31692 handleOut : function(){
31693 if(!this.resizing){
31694 this.el.removeClass("x-resizable-over");
31699 * Returns the element this component is bound to.
31700 * @return {Roo.Element}
31702 getEl : function(){
31707 * Returns the resizeChild element (or null).
31708 * @return {Roo.Element}
31710 getResizeChild : function(){
31711 return this.resizeChild;
31713 groupHandler : function()
31718 * Destroys this resizable. If the element was wrapped and
31719 * removeEl is not true then the element remains.
31720 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
31722 destroy : function(removeEl){
31723 this.proxy.remove();
31725 this.overlay.removeAllListeners();
31726 this.overlay.remove();
31728 var ps = Roo.Resizable.positions;
31730 if(typeof ps[k] != "function" && this[ps[k]]){
31731 var h = this[ps[k]];
31732 h.el.removeAllListeners();
31737 this.el.update("");
31744 // hash to map config positions to true positions
31745 Roo.Resizable.positions = {
31746 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
31751 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
31753 // only initialize the template if resizable is used
31754 var tpl = Roo.DomHelper.createTemplate(
31755 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
31758 Roo.Resizable.Handle.prototype.tpl = tpl;
31760 this.position = pos;
31762 // show north drag fro topdra
31763 var handlepos = pos == 'hdrag' ? 'north' : pos;
31765 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
31766 if (pos == 'hdrag') {
31767 this.el.setStyle('cursor', 'pointer');
31769 this.el.unselectable();
31771 this.el.setOpacity(0);
31773 this.el.on("mousedown", this.onMouseDown, this);
31774 if(!disableTrackOver){
31775 this.el.on("mouseover", this.onMouseOver, this);
31776 this.el.on("mouseout", this.onMouseOut, this);
31781 Roo.Resizable.Handle.prototype = {
31782 afterResize : function(rz){
31787 onMouseDown : function(e){
31788 this.rz.onMouseDown(this, e);
31791 onMouseOver : function(e){
31792 this.rz.handleOver(this, e);
31795 onMouseOut : function(e){
31796 this.rz.handleOut(this, e);
31800 * Ext JS Library 1.1.1
31801 * Copyright(c) 2006-2007, Ext JS, LLC.
31803 * Originally Released Under LGPL - original licence link has changed is not relivant.
31806 * <script type="text/javascript">
31810 * @class Roo.Editor
31811 * @extends Roo.Component
31812 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
31814 * Create a new Editor
31815 * @param {Roo.form.Field} field The Field object (or descendant)
31816 * @param {Object} config The config object
31818 Roo.Editor = function(field, config){
31819 Roo.Editor.superclass.constructor.call(this, config);
31820 this.field = field;
31823 * @event beforestartedit
31824 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
31825 * false from the handler of this event.
31826 * @param {Editor} this
31827 * @param {Roo.Element} boundEl The underlying element bound to this editor
31828 * @param {Mixed} value The field value being set
31830 "beforestartedit" : true,
31833 * Fires when this editor is displayed
31834 * @param {Roo.Element} boundEl The underlying element bound to this editor
31835 * @param {Mixed} value The starting field value
31837 "startedit" : true,
31839 * @event beforecomplete
31840 * Fires after a change has been made to the field, but before the change is reflected in the underlying
31841 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
31842 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
31843 * event will not fire since no edit actually occurred.
31844 * @param {Editor} this
31845 * @param {Mixed} value The current field value
31846 * @param {Mixed} startValue The original field value
31848 "beforecomplete" : true,
31851 * Fires after editing is complete and any changed value has been written to the underlying field.
31852 * @param {Editor} this
31853 * @param {Mixed} value The current field value
31854 * @param {Mixed} startValue The original field value
31858 * @event specialkey
31859 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
31860 * {@link Roo.EventObject#getKey} to determine which key was pressed.
31861 * @param {Roo.form.Field} this
31862 * @param {Roo.EventObject} e The event object
31864 "specialkey" : true
31868 Roo.extend(Roo.Editor, Roo.Component, {
31870 * @cfg {Boolean/String} autosize
31871 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
31872 * or "height" to adopt the height only (defaults to false)
31875 * @cfg {Boolean} revertInvalid
31876 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
31877 * validation fails (defaults to true)
31880 * @cfg {Boolean} ignoreNoChange
31881 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
31882 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
31883 * will never be ignored.
31886 * @cfg {Boolean} hideEl
31887 * False to keep the bound element visible while the editor is displayed (defaults to true)
31890 * @cfg {Mixed} value
31891 * The data value of the underlying field (defaults to "")
31895 * @cfg {String} alignment
31896 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
31900 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
31901 * for bottom-right shadow (defaults to "frame")
31905 * @cfg {Boolean} constrain True to constrain the editor to the viewport
31909 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
31911 completeOnEnter : false,
31913 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
31915 cancelOnEsc : false,
31917 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
31922 onRender : function(ct, position){
31923 this.el = new Roo.Layer({
31924 shadow: this.shadow,
31930 constrain: this.constrain
31932 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
31933 if(this.field.msgTarget != 'title'){
31934 this.field.msgTarget = 'qtip';
31936 this.field.render(this.el);
31938 this.field.el.dom.setAttribute('autocomplete', 'off');
31940 this.field.on("specialkey", this.onSpecialKey, this);
31941 if(this.swallowKeys){
31942 this.field.el.swallowEvent(['keydown','keypress']);
31945 this.field.on("blur", this.onBlur, this);
31946 if(this.field.grow){
31947 this.field.on("autosize", this.el.sync, this.el, {delay:1});
31951 onSpecialKey : function(field, e)
31953 //Roo.log('editor onSpecialKey');
31954 if(this.completeOnEnter && e.getKey() == e.ENTER){
31956 this.completeEdit();
31959 // do not fire special key otherwise it might hide close the editor...
31960 if(e.getKey() == e.ENTER){
31963 if(this.cancelOnEsc && e.getKey() == e.ESC){
31967 this.fireEvent('specialkey', field, e);
31972 * Starts the editing process and shows the editor.
31973 * @param {String/HTMLElement/Element} el The element to edit
31974 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
31975 * to the innerHTML of el.
31977 startEdit : function(el, value){
31979 this.completeEdit();
31981 this.boundEl = Roo.get(el);
31982 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
31983 if(!this.rendered){
31984 this.render(this.parentEl || document.body);
31986 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
31989 this.startValue = v;
31990 this.field.setValue(v);
31992 var sz = this.boundEl.getSize();
31993 switch(this.autoSize){
31995 this.setSize(sz.width, "");
31998 this.setSize("", sz.height);
32001 this.setSize(sz.width, sz.height);
32004 this.el.alignTo(this.boundEl, this.alignment);
32005 this.editing = true;
32007 Roo.QuickTips.disable();
32013 * Sets the height and width of this editor.
32014 * @param {Number} width The new width
32015 * @param {Number} height The new height
32017 setSize : function(w, h){
32018 this.field.setSize(w, h);
32025 * Realigns the editor to the bound field based on the current alignment config value.
32027 realign : function(){
32028 this.el.alignTo(this.boundEl, this.alignment);
32032 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
32033 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
32035 completeEdit : function(remainVisible){
32039 var v = this.getValue();
32040 if(this.revertInvalid !== false && !this.field.isValid()){
32041 v = this.startValue;
32042 this.cancelEdit(true);
32044 if(String(v) === String(this.startValue) && this.ignoreNoChange){
32045 this.editing = false;
32049 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
32050 this.editing = false;
32051 if(this.updateEl && this.boundEl){
32052 this.boundEl.update(v);
32054 if(remainVisible !== true){
32057 this.fireEvent("complete", this, v, this.startValue);
32062 onShow : function(){
32064 if(this.hideEl !== false){
32065 this.boundEl.hide();
32068 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
32069 this.fixIEFocus = true;
32070 this.deferredFocus.defer(50, this);
32072 this.field.focus();
32074 this.fireEvent("startedit", this.boundEl, this.startValue);
32077 deferredFocus : function(){
32079 this.field.focus();
32084 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
32085 * reverted to the original starting value.
32086 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
32087 * cancel (defaults to false)
32089 cancelEdit : function(remainVisible){
32091 this.setValue(this.startValue);
32092 if(remainVisible !== true){
32099 onBlur : function(){
32100 if(this.allowBlur !== true && this.editing){
32101 this.completeEdit();
32106 onHide : function(){
32108 this.completeEdit();
32112 if(this.field.collapse){
32113 this.field.collapse();
32116 if(this.hideEl !== false){
32117 this.boundEl.show();
32120 Roo.QuickTips.enable();
32125 * Sets the data value of the editor
32126 * @param {Mixed} value Any valid value supported by the underlying field
32128 setValue : function(v){
32129 this.field.setValue(v);
32133 * Gets the data value of the editor
32134 * @return {Mixed} The data value
32136 getValue : function(){
32137 return this.field.getValue();
32141 * Ext JS Library 1.1.1
32142 * Copyright(c) 2006-2007, Ext JS, LLC.
32144 * Originally Released Under LGPL - original licence link has changed is not relivant.
32147 * <script type="text/javascript">
32151 * @class Roo.BasicDialog
32152 * @extends Roo.util.Observable
32153 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
32155 var dlg = new Roo.BasicDialog("my-dlg", {
32164 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
32165 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
32166 dlg.addButton('Cancel', dlg.hide, dlg);
32169 <b>A Dialog should always be a direct child of the body element.</b>
32170 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
32171 * @cfg {String} title Default text to display in the title bar (defaults to null)
32172 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
32173 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
32174 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
32175 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
32176 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
32177 * (defaults to null with no animation)
32178 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
32179 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
32180 * property for valid values (defaults to 'all')
32181 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
32182 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
32183 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
32184 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
32185 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
32186 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
32187 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
32188 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
32189 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
32190 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
32191 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
32192 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
32193 * draggable = true (defaults to false)
32194 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
32195 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
32196 * shadow (defaults to false)
32197 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
32198 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
32199 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
32200 * @cfg {Array} buttons Array of buttons
32201 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
32203 * Create a new BasicDialog.
32204 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
32205 * @param {Object} config Configuration options
32207 Roo.BasicDialog = function(el, config){
32208 this.el = Roo.get(el);
32209 var dh = Roo.DomHelper;
32210 if(!this.el && config && config.autoCreate){
32211 if(typeof config.autoCreate == "object"){
32212 if(!config.autoCreate.id){
32213 config.autoCreate.id = el;
32215 this.el = dh.append(document.body,
32216 config.autoCreate, true);
32218 this.el = dh.append(document.body,
32219 {tag: "div", id: el, style:'visibility:hidden;'}, true);
32223 el.setDisplayed(true);
32224 el.hide = this.hideAction;
32226 el.addClass("x-dlg");
32228 Roo.apply(this, config);
32230 this.proxy = el.createProxy("x-dlg-proxy");
32231 this.proxy.hide = this.hideAction;
32232 this.proxy.setOpacity(.5);
32236 el.setWidth(config.width);
32239 el.setHeight(config.height);
32241 this.size = el.getSize();
32242 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
32243 this.xy = [config.x,config.y];
32245 this.xy = el.getCenterXY(true);
32247 /** The header element @type Roo.Element */
32248 this.header = el.child("> .x-dlg-hd");
32249 /** The body element @type Roo.Element */
32250 this.body = el.child("> .x-dlg-bd");
32251 /** The footer element @type Roo.Element */
32252 this.footer = el.child("> .x-dlg-ft");
32255 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
32258 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
32261 this.header.unselectable();
32263 this.header.update(this.title);
32265 // this element allows the dialog to be focused for keyboard event
32266 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
32267 this.focusEl.swallowEvent("click", true);
32269 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
32271 // wrap the body and footer for special rendering
32272 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
32274 this.bwrap.dom.appendChild(this.footer.dom);
32277 this.bg = this.el.createChild({
32278 tag: "div", cls:"x-dlg-bg",
32279 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
32281 this.centerBg = this.bg.child("div.x-dlg-bg-center");
32284 if(this.autoScroll !== false && !this.autoTabs){
32285 this.body.setStyle("overflow", "auto");
32288 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
32290 if(this.closable !== false){
32291 this.el.addClass("x-dlg-closable");
32292 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
32293 this.close.on("click", this.closeClick, this);
32294 this.close.addClassOnOver("x-dlg-close-over");
32296 if(this.collapsible !== false){
32297 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
32298 this.collapseBtn.on("click", this.collapseClick, this);
32299 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
32300 this.header.on("dblclick", this.collapseClick, this);
32302 if(this.resizable !== false){
32303 this.el.addClass("x-dlg-resizable");
32304 this.resizer = new Roo.Resizable(el, {
32305 minWidth: this.minWidth || 80,
32306 minHeight:this.minHeight || 80,
32307 handles: this.resizeHandles || "all",
32310 this.resizer.on("beforeresize", this.beforeResize, this);
32311 this.resizer.on("resize", this.onResize, this);
32313 if(this.draggable !== false){
32314 el.addClass("x-dlg-draggable");
32315 if (!this.proxyDrag) {
32316 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
32319 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
32321 dd.setHandleElId(this.header.id);
32322 dd.endDrag = this.endMove.createDelegate(this);
32323 dd.startDrag = this.startMove.createDelegate(this);
32324 dd.onDrag = this.onDrag.createDelegate(this);
32329 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
32330 this.mask.enableDisplayMode("block");
32332 this.el.addClass("x-dlg-modal");
32335 this.shadow = new Roo.Shadow({
32336 mode : typeof this.shadow == "string" ? this.shadow : "sides",
32337 offset : this.shadowOffset
32340 this.shadowOffset = 0;
32342 if(Roo.useShims && this.shim !== false){
32343 this.shim = this.el.createShim();
32344 this.shim.hide = this.hideAction;
32352 if (this.buttons) {
32353 var bts= this.buttons;
32355 Roo.each(bts, function(b) {
32364 * Fires when a key is pressed
32365 * @param {Roo.BasicDialog} this
32366 * @param {Roo.EventObject} e
32371 * Fires when this dialog is moved by the user.
32372 * @param {Roo.BasicDialog} this
32373 * @param {Number} x The new page X
32374 * @param {Number} y The new page Y
32379 * Fires when this dialog is resized by the user.
32380 * @param {Roo.BasicDialog} this
32381 * @param {Number} width The new width
32382 * @param {Number} height The new height
32386 * @event beforehide
32387 * Fires before this dialog is hidden.
32388 * @param {Roo.BasicDialog} this
32390 "beforehide" : true,
32393 * Fires when this dialog is hidden.
32394 * @param {Roo.BasicDialog} this
32398 * @event beforeshow
32399 * Fires before this dialog is shown.
32400 * @param {Roo.BasicDialog} this
32402 "beforeshow" : true,
32405 * Fires when this dialog is shown.
32406 * @param {Roo.BasicDialog} this
32410 el.on("keydown", this.onKeyDown, this);
32411 el.on("mousedown", this.toFront, this);
32412 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
32414 Roo.DialogManager.register(this);
32415 Roo.BasicDialog.superclass.constructor.call(this);
32418 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
32419 shadowOffset: Roo.isIE ? 6 : 5,
32422 minButtonWidth: 75,
32423 defaultButton: null,
32424 buttonAlign: "right",
32429 * Sets the dialog title text
32430 * @param {String} text The title text to display
32431 * @return {Roo.BasicDialog} this
32433 setTitle : function(text){
32434 this.header.update(text);
32439 closeClick : function(){
32444 collapseClick : function(){
32445 this[this.collapsed ? "expand" : "collapse"]();
32449 * Collapses the dialog to its minimized state (only the title bar is visible).
32450 * Equivalent to the user clicking the collapse dialog button.
32452 collapse : function(){
32453 if(!this.collapsed){
32454 this.collapsed = true;
32455 this.el.addClass("x-dlg-collapsed");
32456 this.restoreHeight = this.el.getHeight();
32457 this.resizeTo(this.el.getWidth(), this.header.getHeight());
32462 * Expands a collapsed dialog back to its normal state. Equivalent to the user
32463 * clicking the expand dialog button.
32465 expand : function(){
32466 if(this.collapsed){
32467 this.collapsed = false;
32468 this.el.removeClass("x-dlg-collapsed");
32469 this.resizeTo(this.el.getWidth(), this.restoreHeight);
32474 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
32475 * @return {Roo.TabPanel} The tabs component
32477 initTabs : function(){
32478 var tabs = this.getTabs();
32479 while(tabs.getTab(0)){
32482 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
32484 tabs.addTab(Roo.id(dom), dom.title);
32492 beforeResize : function(){
32493 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
32497 onResize : function(){
32498 this.refreshSize();
32499 this.syncBodyHeight();
32500 this.adjustAssets();
32502 this.fireEvent("resize", this, this.size.width, this.size.height);
32506 onKeyDown : function(e){
32507 if(this.isVisible()){
32508 this.fireEvent("keydown", this, e);
32513 * Resizes the dialog.
32514 * @param {Number} width
32515 * @param {Number} height
32516 * @return {Roo.BasicDialog} this
32518 resizeTo : function(width, height){
32519 this.el.setSize(width, height);
32520 this.size = {width: width, height: height};
32521 this.syncBodyHeight();
32522 if(this.fixedcenter){
32525 if(this.isVisible()){
32526 this.constrainXY();
32527 this.adjustAssets();
32529 this.fireEvent("resize", this, width, height);
32535 * Resizes the dialog to fit the specified content size.
32536 * @param {Number} width
32537 * @param {Number} height
32538 * @return {Roo.BasicDialog} this
32540 setContentSize : function(w, h){
32541 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
32542 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
32543 //if(!this.el.isBorderBox()){
32544 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
32545 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
32548 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
32549 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
32551 this.resizeTo(w, h);
32556 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
32557 * executed in response to a particular key being pressed while the dialog is active.
32558 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
32559 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
32560 * @param {Function} fn The function to call
32561 * @param {Object} scope (optional) The scope of the function
32562 * @return {Roo.BasicDialog} this
32564 addKeyListener : function(key, fn, scope){
32565 var keyCode, shift, ctrl, alt;
32566 if(typeof key == "object" && !(key instanceof Array)){
32567 keyCode = key["key"];
32568 shift = key["shift"];
32569 ctrl = key["ctrl"];
32574 var handler = function(dlg, e){
32575 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
32576 var k = e.getKey();
32577 if(keyCode instanceof Array){
32578 for(var i = 0, len = keyCode.length; i < len; i++){
32579 if(keyCode[i] == k){
32580 fn.call(scope || window, dlg, k, e);
32586 fn.call(scope || window, dlg, k, e);
32591 this.on("keydown", handler);
32596 * Returns the TabPanel component (creates it if it doesn't exist).
32597 * Note: If you wish to simply check for the existence of tabs without creating them,
32598 * check for a null 'tabs' property.
32599 * @return {Roo.TabPanel} The tabs component
32601 getTabs : function(){
32603 this.el.addClass("x-dlg-auto-tabs");
32604 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
32605 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
32611 * Adds a button to the footer section of the dialog.
32612 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
32613 * object or a valid Roo.DomHelper element config
32614 * @param {Function} handler The function called when the button is clicked
32615 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
32616 * @return {Roo.Button} The new button
32618 addButton : function(config, handler, scope){
32619 var dh = Roo.DomHelper;
32621 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
32623 if(!this.btnContainer){
32624 var tb = this.footer.createChild({
32626 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
32627 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
32629 this.btnContainer = tb.firstChild.firstChild.firstChild;
32634 minWidth: this.minButtonWidth,
32637 if(typeof config == "string"){
32638 bconfig.text = config;
32641 bconfig.dhconfig = config;
32643 Roo.apply(bconfig, config);
32647 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
32648 bconfig.position = Math.max(0, bconfig.position);
32649 fc = this.btnContainer.childNodes[bconfig.position];
32652 var btn = new Roo.Button(
32654 this.btnContainer.insertBefore(document.createElement("td"),fc)
32655 : this.btnContainer.appendChild(document.createElement("td")),
32656 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
32659 this.syncBodyHeight();
32662 * Array of all the buttons that have been added to this dialog via addButton
32667 this.buttons.push(btn);
32672 * Sets the default button to be focused when the dialog is displayed.
32673 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
32674 * @return {Roo.BasicDialog} this
32676 setDefaultButton : function(btn){
32677 this.defaultButton = btn;
32682 getHeaderFooterHeight : function(safe){
32685 height += this.header.getHeight();
32688 var fm = this.footer.getMargins();
32689 height += (this.footer.getHeight()+fm.top+fm.bottom);
32691 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
32692 height += this.centerBg.getPadding("tb");
32697 syncBodyHeight : function()
32699 var bd = this.body, // the text
32700 cb = this.centerBg, // wrapper around bottom.. but does not seem to be used..
32702 var height = this.size.height - this.getHeaderFooterHeight(false);
32703 bd.setHeight(height-bd.getMargins("tb"));
32704 var hh = this.header.getHeight();
32705 var h = this.size.height-hh;
32708 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
32709 bw.setHeight(h-cb.getPadding("tb"));
32711 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
32712 bd.setWidth(bw.getWidth(true));
32714 this.tabs.syncHeight();
32716 this.tabs.el.repaint();
32722 * Restores the previous state of the dialog if Roo.state is configured.
32723 * @return {Roo.BasicDialog} this
32725 restoreState : function(){
32726 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
32727 if(box && box.width){
32728 this.xy = [box.x, box.y];
32729 this.resizeTo(box.width, box.height);
32735 beforeShow : function(){
32737 if(this.fixedcenter){
32738 this.xy = this.el.getCenterXY(true);
32741 Roo.get(document.body).addClass("x-body-masked");
32742 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
32745 this.constrainXY();
32749 animShow : function(){
32750 var b = Roo.get(this.animateTarget).getBox();
32751 this.proxy.setSize(b.width, b.height);
32752 this.proxy.setLocation(b.x, b.y);
32754 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
32755 true, .35, this.showEl.createDelegate(this));
32759 * Shows the dialog.
32760 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
32761 * @return {Roo.BasicDialog} this
32763 show : function(animateTarget){
32764 if (this.fireEvent("beforeshow", this) === false){
32767 if(this.syncHeightBeforeShow){
32768 this.syncBodyHeight();
32769 }else if(this.firstShow){
32770 this.firstShow = false;
32771 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
32773 this.animateTarget = animateTarget || this.animateTarget;
32774 if(!this.el.isVisible()){
32776 if(this.animateTarget && Roo.get(this.animateTarget)){
32786 showEl : function(){
32788 this.el.setXY(this.xy);
32790 this.adjustAssets(true);
32793 // IE peekaboo bug - fix found by Dave Fenwick
32797 this.fireEvent("show", this);
32801 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
32802 * dialog itself will receive focus.
32804 focus : function(){
32805 if(this.defaultButton){
32806 this.defaultButton.focus();
32808 this.focusEl.focus();
32813 constrainXY : function(){
32814 if(this.constraintoviewport !== false){
32815 if(!this.viewSize){
32816 if(this.container){
32817 var s = this.container.getSize();
32818 this.viewSize = [s.width, s.height];
32820 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
32823 var s = Roo.get(this.container||document).getScroll();
32825 var x = this.xy[0], y = this.xy[1];
32826 var w = this.size.width, h = this.size.height;
32827 var vw = this.viewSize[0], vh = this.viewSize[1];
32828 // only move it if it needs it
32830 // first validate right/bottom
32831 if(x + w > vw+s.left){
32835 if(y + h > vh+s.top){
32839 // then make sure top/left isn't negative
32851 if(this.isVisible()){
32852 this.el.setLocation(x, y);
32853 this.adjustAssets();
32860 onDrag : function(){
32861 if(!this.proxyDrag){
32862 this.xy = this.el.getXY();
32863 this.adjustAssets();
32868 adjustAssets : function(doShow){
32869 var x = this.xy[0], y = this.xy[1];
32870 var w = this.size.width, h = this.size.height;
32871 if(doShow === true){
32873 this.shadow.show(this.el);
32879 if(this.shadow && this.shadow.isVisible()){
32880 this.shadow.show(this.el);
32882 if(this.shim && this.shim.isVisible()){
32883 this.shim.setBounds(x, y, w, h);
32888 adjustViewport : function(w, h){
32890 w = Roo.lib.Dom.getViewWidth();
32891 h = Roo.lib.Dom.getViewHeight();
32894 this.viewSize = [w, h];
32895 if(this.modal && this.mask.isVisible()){
32896 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
32897 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
32899 if(this.isVisible()){
32900 this.constrainXY();
32905 * Destroys this dialog and all its supporting elements (including any tabs, shim,
32906 * shadow, proxy, mask, etc.) Also removes all event listeners.
32907 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
32909 destroy : function(removeEl){
32910 if(this.isVisible()){
32911 this.animateTarget = null;
32914 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
32916 this.tabs.destroy(removeEl);
32929 for(var i = 0, len = this.buttons.length; i < len; i++){
32930 this.buttons[i].destroy();
32933 this.el.removeAllListeners();
32934 if(removeEl === true){
32935 this.el.update("");
32938 Roo.DialogManager.unregister(this);
32942 startMove : function(){
32943 if(this.proxyDrag){
32946 if(this.constraintoviewport !== false){
32947 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
32952 endMove : function(){
32953 if(!this.proxyDrag){
32954 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
32956 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
32959 this.refreshSize();
32960 this.adjustAssets();
32962 this.fireEvent("move", this, this.xy[0], this.xy[1]);
32966 * Brings this dialog to the front of any other visible dialogs
32967 * @return {Roo.BasicDialog} this
32969 toFront : function(){
32970 Roo.DialogManager.bringToFront(this);
32975 * Sends this dialog to the back (under) of any other visible dialogs
32976 * @return {Roo.BasicDialog} this
32978 toBack : function(){
32979 Roo.DialogManager.sendToBack(this);
32984 * Centers this dialog in the viewport
32985 * @return {Roo.BasicDialog} this
32987 center : function(){
32988 var xy = this.el.getCenterXY(true);
32989 this.moveTo(xy[0], xy[1]);
32994 * Moves the dialog's top-left corner to the specified point
32995 * @param {Number} x
32996 * @param {Number} y
32997 * @return {Roo.BasicDialog} this
32999 moveTo : function(x, y){
33001 if(this.isVisible()){
33002 this.el.setXY(this.xy);
33003 this.adjustAssets();
33009 * Aligns the dialog to the specified element
33010 * @param {String/HTMLElement/Roo.Element} element The element to align to.
33011 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
33012 * @param {Array} offsets (optional) Offset the positioning by [x, y]
33013 * @return {Roo.BasicDialog} this
33015 alignTo : function(element, position, offsets){
33016 this.xy = this.el.getAlignToXY(element, position, offsets);
33017 if(this.isVisible()){
33018 this.el.setXY(this.xy);
33019 this.adjustAssets();
33025 * Anchors an element to another element and realigns it when the window is resized.
33026 * @param {String/HTMLElement/Roo.Element} element The element to align to.
33027 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
33028 * @param {Array} offsets (optional) Offset the positioning by [x, y]
33029 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
33030 * is a number, it is used as the buffer delay (defaults to 50ms).
33031 * @return {Roo.BasicDialog} this
33033 anchorTo : function(el, alignment, offsets, monitorScroll){
33034 var action = function(){
33035 this.alignTo(el, alignment, offsets);
33037 Roo.EventManager.onWindowResize(action, this);
33038 var tm = typeof monitorScroll;
33039 if(tm != 'undefined'){
33040 Roo.EventManager.on(window, 'scroll', action, this,
33041 {buffer: tm == 'number' ? monitorScroll : 50});
33048 * Returns true if the dialog is visible
33049 * @return {Boolean}
33051 isVisible : function(){
33052 return this.el.isVisible();
33056 animHide : function(callback){
33057 var b = Roo.get(this.animateTarget).getBox();
33059 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
33061 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
33062 this.hideEl.createDelegate(this, [callback]));
33066 * Hides the dialog.
33067 * @param {Function} callback (optional) Function to call when the dialog is hidden
33068 * @return {Roo.BasicDialog} this
33070 hide : function(callback){
33071 if (this.fireEvent("beforehide", this) === false){
33075 this.shadow.hide();
33080 // sometimes animateTarget seems to get set.. causing problems...
33081 // this just double checks..
33082 if(this.animateTarget && Roo.get(this.animateTarget)) {
33083 this.animHide(callback);
33086 this.hideEl(callback);
33092 hideEl : function(callback){
33096 Roo.get(document.body).removeClass("x-body-masked");
33098 this.fireEvent("hide", this);
33099 if(typeof callback == "function"){
33105 hideAction : function(){
33106 this.setLeft("-10000px");
33107 this.setTop("-10000px");
33108 this.setStyle("visibility", "hidden");
33112 refreshSize : function(){
33113 this.size = this.el.getSize();
33114 this.xy = this.el.getXY();
33115 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
33119 // z-index is managed by the DialogManager and may be overwritten at any time
33120 setZIndex : function(index){
33122 this.mask.setStyle("z-index", index);
33125 this.shim.setStyle("z-index", ++index);
33128 this.shadow.setZIndex(++index);
33130 this.el.setStyle("z-index", ++index);
33132 this.proxy.setStyle("z-index", ++index);
33135 this.resizer.proxy.setStyle("z-index", ++index);
33138 this.lastZIndex = index;
33142 * Returns the element for this dialog
33143 * @return {Roo.Element} The underlying dialog Element
33145 getEl : function(){
33151 * @class Roo.DialogManager
33152 * Provides global access to BasicDialogs that have been created and
33153 * support for z-indexing (layering) multiple open dialogs.
33155 Roo.DialogManager = function(){
33157 var accessList = [];
33161 var sortDialogs = function(d1, d2){
33162 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
33166 var orderDialogs = function(){
33167 accessList.sort(sortDialogs);
33168 var seed = Roo.DialogManager.zseed;
33169 for(var i = 0, len = accessList.length; i < len; i++){
33170 var dlg = accessList[i];
33172 dlg.setZIndex(seed + (i*10));
33179 * The starting z-index for BasicDialogs (defaults to 9000)
33180 * @type Number The z-index value
33185 register : function(dlg){
33186 list[dlg.id] = dlg;
33187 accessList.push(dlg);
33191 unregister : function(dlg){
33192 delete list[dlg.id];
33195 if(!accessList.indexOf){
33196 for( i = 0, len = accessList.length; i < len; i++){
33197 if(accessList[i] == dlg){
33198 accessList.splice(i, 1);
33203 i = accessList.indexOf(dlg);
33205 accessList.splice(i, 1);
33211 * Gets a registered dialog by id
33212 * @param {String/Object} id The id of the dialog or a dialog
33213 * @return {Roo.BasicDialog} this
33215 get : function(id){
33216 return typeof id == "object" ? id : list[id];
33220 * Brings the specified dialog to the front
33221 * @param {String/Object} dlg The id of the dialog or a dialog
33222 * @return {Roo.BasicDialog} this
33224 bringToFront : function(dlg){
33225 dlg = this.get(dlg);
33228 dlg._lastAccess = new Date().getTime();
33235 * Sends the specified dialog to the back
33236 * @param {String/Object} dlg The id of the dialog or a dialog
33237 * @return {Roo.BasicDialog} this
33239 sendToBack : function(dlg){
33240 dlg = this.get(dlg);
33241 dlg._lastAccess = -(new Date().getTime());
33247 * Hides all dialogs
33249 hideAll : function(){
33250 for(var id in list){
33251 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
33260 * @class Roo.LayoutDialog
33261 * @extends Roo.BasicDialog
33262 * @children Roo.ContentPanel
33264 * Dialog which provides adjustments for working with a layout in a Dialog.
33265 * Add your necessary layout config options to the dialog's config.<br>
33266 * Example usage (including a nested layout):
33269 dialog = new Roo.LayoutDialog("download-dlg", {
33278 // layout config merges with the dialog config
33280 tabPosition: "top",
33281 alwaysShowTabs: true
33284 dialog.addKeyListener(27, dialog.hide, dialog);
33285 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
33286 dialog.addButton("Build It!", this.getDownload, this);
33288 // we can even add nested layouts
33289 var innerLayout = new Roo.BorderLayout("dl-inner", {
33299 innerLayout.beginUpdate();
33300 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
33301 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
33302 innerLayout.endUpdate(true);
33304 var layout = dialog.getLayout();
33305 layout.beginUpdate();
33306 layout.add("center", new Roo.ContentPanel("standard-panel",
33307 {title: "Download the Source", fitToFrame:true}));
33308 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
33309 {title: "Build your own roo.js"}));
33310 layout.getRegion("center").showPanel(sp);
33311 layout.endUpdate();
33315 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
33316 * @param {Object} config configuration options
33318 Roo.LayoutDialog = function(el, cfg){
33321 if (typeof(cfg) == 'undefined') {
33322 config = Roo.apply({}, el);
33323 // not sure why we use documentElement here.. - it should always be body.
33324 // IE7 borks horribly if we use documentElement.
33325 // webkit also does not like documentElement - it creates a body element...
33326 el = Roo.get( document.body || document.documentElement ).createChild();
33327 //config.autoCreate = true;
33331 config.autoTabs = false;
33332 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
33333 this.body.setStyle({overflow:"hidden", position:"relative"});
33334 this.layout = new Roo.BorderLayout(this.body.dom, config);
33335 this.layout.monitorWindowResize = false;
33336 this.el.addClass("x-dlg-auto-layout");
33337 // fix case when center region overwrites center function
33338 this.center = Roo.BasicDialog.prototype.center;
33339 this.on("show", this.layout.layout, this.layout, true);
33340 if (config.items) {
33341 var xitems = config.items;
33342 delete config.items;
33343 Roo.each(xitems, this.addxtype, this);
33348 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
33352 * @cfg {Roo.LayoutRegion} east
33355 * @cfg {Roo.LayoutRegion} west
33358 * @cfg {Roo.LayoutRegion} south
33361 * @cfg {Roo.LayoutRegion} north
33364 * @cfg {Roo.LayoutRegion} center
33367 * @cfg {Roo.Button} buttons[] Bottom buttons..
33372 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
33375 endUpdate : function(){
33376 this.layout.endUpdate();
33380 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
33383 beginUpdate : function(){
33384 this.layout.beginUpdate();
33388 * Get the BorderLayout for this dialog
33389 * @return {Roo.BorderLayout}
33391 getLayout : function(){
33392 return this.layout;
33395 showEl : function(){
33396 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
33398 this.layout.layout();
33403 // Use the syncHeightBeforeShow config option to control this automatically
33404 syncBodyHeight : function(){
33405 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
33406 if(this.layout){this.layout.layout();}
33410 * Add an xtype element (actually adds to the layout.)
33411 * @return {Object} xdata xtype object data.
33414 addxtype : function(c) {
33415 return this.layout.addxtype(c);
33419 * Ext JS Library 1.1.1
33420 * Copyright(c) 2006-2007, Ext JS, LLC.
33422 * Originally Released Under LGPL - original licence link has changed is not relivant.
33425 * <script type="text/javascript">
33429 * @class Roo.MessageBox
33430 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
33434 Roo.Msg.alert('Status', 'Changes saved successfully.');
33436 // Prompt for user data:
33437 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
33439 // process text value...
33443 // Show a dialog using config options:
33445 title:'Save Changes?',
33446 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
33447 buttons: Roo.Msg.YESNOCANCEL,
33454 Roo.MessageBox = function(){
33455 var dlg, opt, mask, waitTimer;
33456 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
33457 var buttons, activeTextEl, bwidth;
33460 var handleButton = function(button){
33462 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
33466 var handleHide = function(){
33467 if(opt && opt.cls){
33468 dlg.el.removeClass(opt.cls);
33471 Roo.TaskMgr.stop(waitTimer);
33477 var updateButtons = function(b){
33480 buttons["ok"].hide();
33481 buttons["cancel"].hide();
33482 buttons["yes"].hide();
33483 buttons["no"].hide();
33484 dlg.footer.dom.style.display = 'none';
33487 dlg.footer.dom.style.display = '';
33488 for(var k in buttons){
33489 if(typeof buttons[k] != "function"){
33492 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
33493 width += buttons[k].el.getWidth()+15;
33503 var handleEsc = function(d, k, e){
33504 if(opt && opt.closable !== false){
33514 * Returns a reference to the underlying {@link Roo.BasicDialog} element
33515 * @return {Roo.BasicDialog} The BasicDialog element
33517 getDialog : function(){
33519 dlg = new Roo.BasicDialog("x-msg-box", {
33524 constraintoviewport:false,
33526 collapsible : false,
33529 width:400, height:100,
33530 buttonAlign:"center",
33531 closeClick : function(){
33532 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
33533 handleButton("no");
33535 handleButton("cancel");
33539 dlg.on("hide", handleHide);
33541 dlg.addKeyListener(27, handleEsc);
33543 var bt = this.buttonText;
33544 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
33545 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
33546 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
33547 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
33548 bodyEl = dlg.body.createChild({
33550 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>'
33552 msgEl = bodyEl.dom.firstChild;
33553 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
33554 textboxEl.enableDisplayMode();
33555 textboxEl.addKeyListener([10,13], function(){
33556 if(dlg.isVisible() && opt && opt.buttons){
33557 if(opt.buttons.ok){
33558 handleButton("ok");
33559 }else if(opt.buttons.yes){
33560 handleButton("yes");
33564 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
33565 textareaEl.enableDisplayMode();
33566 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
33567 progressEl.enableDisplayMode();
33568 var pf = progressEl.dom.firstChild;
33570 pp = Roo.get(pf.firstChild);
33571 pp.setHeight(pf.offsetHeight);
33579 * Updates the message box body text
33580 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
33581 * the XHTML-compliant non-breaking space character '&#160;')
33582 * @return {Roo.MessageBox} This message box
33584 updateText : function(text){
33585 if(!dlg.isVisible() && !opt.width){
33586 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
33588 msgEl.innerHTML = text || ' ';
33590 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
33591 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
33593 Math.min(opt.width || cw , this.maxWidth),
33594 Math.max(opt.minWidth || this.minWidth, bwidth)
33597 activeTextEl.setWidth(w);
33599 if(dlg.isVisible()){
33600 dlg.fixedcenter = false;
33602 // to big, make it scroll. = But as usual stupid IE does not support
33605 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
33606 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
33607 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
33609 bodyEl.dom.style.height = '';
33610 bodyEl.dom.style.overflowY = '';
33613 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
33615 bodyEl.dom.style.overflowX = '';
33618 dlg.setContentSize(w, bodyEl.getHeight());
33619 if(dlg.isVisible()){
33620 dlg.fixedcenter = true;
33626 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
33627 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
33628 * @param {Number} value Any number between 0 and 1 (e.g., .5)
33629 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
33630 * @return {Roo.MessageBox} This message box
33632 updateProgress : function(value, text){
33634 this.updateText(text);
33636 if (pp) { // weird bug on my firefox - for some reason this is not defined
33637 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
33643 * Returns true if the message box is currently displayed
33644 * @return {Boolean} True if the message box is visible, else false
33646 isVisible : function(){
33647 return dlg && dlg.isVisible();
33651 * Hides the message box if it is displayed
33654 if(this.isVisible()){
33660 * Displays a new message box, or reinitializes an existing message box, based on the config options
33661 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
33662 * The following config object properties are supported:
33664 Property Type Description
33665 ---------- --------------- ------------------------------------------------------------------------------------
33666 animEl String/Element An id or Element from which the message box should animate as it opens and
33667 closes (defaults to undefined)
33668 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
33669 cancel:'Bar'}), or false to not show any buttons (defaults to false)
33670 closable Boolean False to hide the top-right close button (defaults to true). Note that
33671 progress and wait dialogs will ignore this property and always hide the
33672 close button as they can only be closed programmatically.
33673 cls String A custom CSS class to apply to the message box element
33674 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
33675 displayed (defaults to 75)
33676 fn Function A callback function to execute after closing the dialog. The arguments to the
33677 function will be btn (the name of the button that was clicked, if applicable,
33678 e.g. "ok"), and text (the value of the active text field, if applicable).
33679 Progress and wait dialogs will ignore this option since they do not respond to
33680 user actions and can only be closed programmatically, so any required function
33681 should be called by the same code after it closes the dialog.
33682 icon String A CSS class that provides a background image to be used as an icon for
33683 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
33684 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
33685 minWidth Number The minimum width in pixels of the message box (defaults to 100)
33686 modal Boolean False to allow user interaction with the page while the message box is
33687 displayed (defaults to true)
33688 msg String A string that will replace the existing message box body text (defaults
33689 to the XHTML-compliant non-breaking space character ' ')
33690 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
33691 progress Boolean True to display a progress bar (defaults to false)
33692 progressText String The text to display inside the progress bar if progress = true (defaults to '')
33693 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
33694 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
33695 title String The title text
33696 value String The string value to set into the active textbox element if displayed
33697 wait Boolean True to display a progress bar (defaults to false)
33698 width Number The width of the dialog in pixels
33705 msg: 'Please enter your address:',
33707 buttons: Roo.MessageBox.OKCANCEL,
33710 animEl: 'addAddressBtn'
33713 * @param {Object} config Configuration options
33714 * @return {Roo.MessageBox} This message box
33716 show : function(options)
33719 // this causes nightmares if you show one dialog after another
33720 // especially on callbacks..
33722 if(this.isVisible()){
33725 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
33726 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
33727 Roo.log("New Dialog Message:" + options.msg )
33728 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
33729 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
33732 var d = this.getDialog();
33734 d.setTitle(opt.title || " ");
33735 d.close.setDisplayed(opt.closable !== false);
33736 activeTextEl = textboxEl;
33737 opt.prompt = opt.prompt || (opt.multiline ? true : false);
33742 textareaEl.setHeight(typeof opt.multiline == "number" ?
33743 opt.multiline : this.defaultTextHeight);
33744 activeTextEl = textareaEl;
33753 progressEl.setDisplayed(opt.progress === true);
33754 this.updateProgress(0);
33755 activeTextEl.dom.value = opt.value || "";
33757 dlg.setDefaultButton(activeTextEl);
33759 var bs = opt.buttons;
33762 db = buttons["ok"];
33763 }else if(bs && bs.yes){
33764 db = buttons["yes"];
33766 dlg.setDefaultButton(db);
33768 bwidth = updateButtons(opt.buttons);
33769 this.updateText(opt.msg);
33771 d.el.addClass(opt.cls);
33773 d.proxyDrag = opt.proxyDrag === true;
33774 d.modal = opt.modal !== false;
33775 d.mask = opt.modal !== false ? mask : false;
33776 if(!d.isVisible()){
33777 // force it to the end of the z-index stack so it gets a cursor in FF
33778 document.body.appendChild(dlg.el.dom);
33779 d.animateTarget = null;
33780 d.show(options.animEl);
33786 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
33787 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
33788 * and closing the message box when the process is complete.
33789 * @param {String} title The title bar text
33790 * @param {String} msg The message box body text
33791 * @return {Roo.MessageBox} This message box
33793 progress : function(title, msg){
33800 minWidth: this.minProgressWidth,
33807 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
33808 * If a callback function is passed it will be called after the user clicks the button, and the
33809 * id of the button that was clicked will be passed as the only parameter to the callback
33810 * (could also be the top-right close button).
33811 * @param {String} title The title bar text
33812 * @param {String} msg The message box body text
33813 * @param {Function} fn (optional) The callback function invoked after the message box is closed
33814 * @param {Object} scope (optional) The scope of the callback function
33815 * @return {Roo.MessageBox} This message box
33817 alert : function(title, msg, fn, scope){
33830 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
33831 * interaction while waiting for a long-running process to complete that does not have defined intervals.
33832 * You are responsible for closing the message box when the process is complete.
33833 * @param {String} msg The message box body text
33834 * @param {String} title (optional) The title bar text
33835 * @return {Roo.MessageBox} This message box
33837 wait : function(msg, title){
33848 waitTimer = Roo.TaskMgr.start({
33850 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
33858 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
33859 * If a callback function is passed it will be called after the user clicks either button, and the id of the
33860 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
33861 * @param {String} title The title bar text
33862 * @param {String} msg The message box body text
33863 * @param {Function} fn (optional) The callback function invoked after the message box is closed
33864 * @param {Object} scope (optional) The scope of the callback function
33865 * @return {Roo.MessageBox} This message box
33867 confirm : function(title, msg, fn, scope){
33871 buttons: this.YESNO,
33880 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
33881 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
33882 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
33883 * (could also be the top-right close button) and the text that was entered will be passed as the two
33884 * parameters to the callback.
33885 * @param {String} title The title bar text
33886 * @param {String} msg The message box body text
33887 * @param {Function} fn (optional) The callback function invoked after the message box is closed
33888 * @param {Object} scope (optional) The scope of the callback function
33889 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
33890 * property, or the height in pixels to create the textbox (defaults to false / single-line)
33891 * @return {Roo.MessageBox} This message box
33893 prompt : function(title, msg, fn, scope, multiline){
33897 buttons: this.OKCANCEL,
33902 multiline: multiline,
33909 * Button config that displays a single OK button
33914 * Button config that displays Yes and No buttons
33917 YESNO : {yes:true, no:true},
33919 * Button config that displays OK and Cancel buttons
33922 OKCANCEL : {ok:true, cancel:true},
33924 * Button config that displays Yes, No and Cancel buttons
33927 YESNOCANCEL : {yes:true, no:true, cancel:true},
33930 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
33933 defaultTextHeight : 75,
33935 * The maximum width in pixels of the message box (defaults to 600)
33940 * The minimum width in pixels of the message box (defaults to 100)
33945 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
33946 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
33949 minProgressWidth : 250,
33951 * An object containing the default button text strings that can be overriden for localized language support.
33952 * Supported properties are: ok, cancel, yes and no.
33953 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
33966 * Shorthand for {@link Roo.MessageBox}
33968 Roo.Msg = Roo.MessageBox;/*
33970 * Ext JS Library 1.1.1
33971 * Copyright(c) 2006-2007, Ext JS, LLC.
33973 * Originally Released Under LGPL - original licence link has changed is not relivant.
33976 * <script type="text/javascript">
33979 * @class Roo.QuickTips
33980 * Provides attractive and customizable tooltips for any element.
33983 Roo.QuickTips = function(){
33984 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
33985 var ce, bd, xy, dd;
33986 var visible = false, disabled = true, inited = false;
33987 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
33989 var onOver = function(e){
33993 var t = e.getTarget();
33994 if(!t || t.nodeType !== 1 || t == document || t == document.body){
33997 if(ce && t == ce.el){
33998 clearTimeout(hideProc);
34001 if(t && tagEls[t.id]){
34002 tagEls[t.id].el = t;
34003 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
34006 var ttp, et = Roo.fly(t);
34007 var ns = cfg.namespace;
34008 if(tm.interceptTitles && t.title){
34011 t.removeAttribute("title");
34012 e.preventDefault();
34014 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute) || et.getAttributeNS(cfg.alt_namespace, cfg.attribute) ;
34017 showProc = show.defer(tm.showDelay, tm, [{
34019 text: ttp.replace(/\\n/g,'<br/>'),
34020 width: et.getAttributeNS(ns, cfg.width),
34021 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
34022 title: et.getAttributeNS(ns, cfg.title),
34023 cls: et.getAttributeNS(ns, cfg.cls)
34028 var onOut = function(e){
34029 clearTimeout(showProc);
34030 var t = e.getTarget();
34031 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
34032 hideProc = setTimeout(hide, tm.hideDelay);
34036 var onMove = function(e){
34042 if(tm.trackMouse && ce){
34047 var onDown = function(e){
34048 clearTimeout(showProc);
34049 clearTimeout(hideProc);
34051 if(tm.hideOnClick){
34054 tm.enable.defer(100, tm);
34059 var getPad = function(){
34060 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
34063 var show = function(o){
34067 clearTimeout(dismissProc);
34069 if(removeCls){ // in case manually hidden
34070 el.removeClass(removeCls);
34074 el.addClass(ce.cls);
34075 removeCls = ce.cls;
34078 tipTitle.update(ce.title);
34081 tipTitle.update('');
34084 el.dom.style.width = tm.maxWidth+'px';
34085 //tipBody.dom.style.width = '';
34086 tipBodyText.update(o.text);
34087 var p = getPad(), w = ce.width;
34089 var td = tipBodyText.dom;
34090 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
34091 if(aw > tm.maxWidth){
34093 }else if(aw < tm.minWidth){
34099 //tipBody.setWidth(w);
34100 el.setWidth(parseInt(w, 10) + p);
34101 if(ce.autoHide === false){
34102 close.setDisplayed(true);
34107 close.setDisplayed(false);
34113 el.avoidY = xy[1]-18;
34118 el.setStyle("visibility", "visible");
34119 el.fadeIn({callback: afterShow});
34125 var afterShow = function(){
34129 if(tm.autoDismiss && ce.autoHide !== false){
34130 dismissProc = setTimeout(hide, tm.autoDismissDelay);
34135 var hide = function(noanim){
34136 clearTimeout(dismissProc);
34137 clearTimeout(hideProc);
34139 if(el.isVisible()){
34141 if(noanim !== true && tm.animate){
34142 el.fadeOut({callback: afterHide});
34149 var afterHide = function(){
34152 el.removeClass(removeCls);
34159 * @cfg {Number} minWidth
34160 * The minimum width of the quick tip (defaults to 40)
34164 * @cfg {Number} maxWidth
34165 * The maximum width of the quick tip (defaults to 300)
34169 * @cfg {Boolean} interceptTitles
34170 * True to automatically use the element's DOM title value if available (defaults to false)
34172 interceptTitles : false,
34174 * @cfg {Boolean} trackMouse
34175 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
34177 trackMouse : false,
34179 * @cfg {Boolean} hideOnClick
34180 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
34182 hideOnClick : true,
34184 * @cfg {Number} showDelay
34185 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
34189 * @cfg {Number} hideDelay
34190 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
34194 * @cfg {Boolean} autoHide
34195 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
34196 * Used in conjunction with hideDelay.
34201 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
34202 * (defaults to true). Used in conjunction with autoDismissDelay.
34204 autoDismiss : true,
34207 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
34209 autoDismissDelay : 5000,
34211 * @cfg {Boolean} animate
34212 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
34217 * @cfg {String} title
34218 * Title text to display (defaults to ''). This can be any valid HTML markup.
34222 * @cfg {String} text
34223 * Body text to display (defaults to ''). This can be any valid HTML markup.
34227 * @cfg {String} cls
34228 * A CSS class to apply to the base quick tip element (defaults to '').
34232 * @cfg {Number} width
34233 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
34234 * minWidth or maxWidth.
34239 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
34240 * or display QuickTips in a page.
34243 tm = Roo.QuickTips;
34244 cfg = tm.tagConfig;
34246 if(!Roo.isReady){ // allow calling of init() before onReady
34247 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
34250 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
34251 el.fxDefaults = {stopFx: true};
34252 // maximum custom styling
34253 //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>');
34254 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>');
34255 tipTitle = el.child('h3');
34256 tipTitle.enableDisplayMode("block");
34257 tipBody = el.child('div.x-tip-bd');
34258 tipBodyText = el.child('div.x-tip-bd-inner');
34259 //bdLeft = el.child('div.x-tip-bd-left');
34260 //bdRight = el.child('div.x-tip-bd-right');
34261 close = el.child('div.x-tip-close');
34262 close.enableDisplayMode("block");
34263 close.on("click", hide);
34264 var d = Roo.get(document);
34265 d.on("mousedown", onDown);
34266 d.on("mouseover", onOver);
34267 d.on("mouseout", onOut);
34268 d.on("mousemove", onMove);
34269 esc = d.addKeyListener(27, hide);
34272 dd = el.initDD("default", null, {
34273 onDrag : function(){
34277 dd.setHandleElId(tipTitle.id);
34286 * Configures a new quick tip instance and assigns it to a target element. The following config options
34289 Property Type Description
34290 ---------- --------------------- ------------------------------------------------------------------------
34291 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
34293 * @param {Object} config The config object
34295 register : function(config){
34296 var cs = config instanceof Array ? config : arguments;
34297 for(var i = 0, len = cs.length; i < len; i++) {
34299 var target = c.target;
34301 if(target instanceof Array){
34302 for(var j = 0, jlen = target.length; j < jlen; j++){
34303 tagEls[target[j]] = c;
34306 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
34313 * Removes this quick tip from its element and destroys it.
34314 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
34316 unregister : function(el){
34317 delete tagEls[Roo.id(el)];
34321 * Enable this quick tip.
34323 enable : function(){
34324 if(inited && disabled){
34326 if(locks.length < 1){
34333 * Disable this quick tip.
34335 disable : function(){
34337 clearTimeout(showProc);
34338 clearTimeout(hideProc);
34339 clearTimeout(dismissProc);
34347 * Returns true if the quick tip is enabled, else false.
34349 isEnabled : function(){
34355 namespace : "roo", // was ext?? this may break..
34356 alt_namespace : "ext",
34357 attribute : "qtip",
34367 // backwards compat
34368 Roo.QuickTips.tips = Roo.QuickTips.register;/*
34370 * Ext JS Library 1.1.1
34371 * Copyright(c) 2006-2007, Ext JS, LLC.
34373 * Originally Released Under LGPL - original licence link has changed is not relivant.
34376 * <script type="text/javascript">
34381 * @class Roo.tree.TreePanel
34382 * @extends Roo.data.Tree
34383 * @cfg {Roo.tree.TreeNode} root The root node
34384 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
34385 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
34386 * @cfg {Boolean} enableDD true to enable drag and drop
34387 * @cfg {Boolean} enableDrag true to enable just drag
34388 * @cfg {Boolean} enableDrop true to enable just drop
34389 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
34390 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
34391 * @cfg {String} ddGroup The DD group this TreePanel belongs to
34392 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
34393 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
34394 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
34395 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
34396 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
34397 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
34398 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
34399 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
34400 * @cfg {Roo.tree.TreeLoader} loader A TreeLoader for use with this TreePanel
34401 * @cfg {Roo.tree.TreeEditor} editor The TreeEditor to display when clicked.
34402 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
34403 * @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>
34404 * @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>
34407 * @param {String/HTMLElement/Element} el The container element
34408 * @param {Object} config
34410 Roo.tree.TreePanel = function(el, config){
34412 var loader = false;
34414 root = config.root;
34415 delete config.root;
34417 if (config.loader) {
34418 loader = config.loader;
34419 delete config.loader;
34422 Roo.apply(this, config);
34423 Roo.tree.TreePanel.superclass.constructor.call(this);
34424 this.el = Roo.get(el);
34425 this.el.addClass('x-tree');
34426 //console.log(root);
34428 this.setRootNode( Roo.factory(root, Roo.tree));
34431 this.loader = Roo.factory(loader, Roo.tree);
34434 * Read-only. The id of the container element becomes this TreePanel's id.
34436 this.id = this.el.id;
34439 * @event beforeload
34440 * Fires before a node is loaded, return false to cancel
34441 * @param {Node} node The node being loaded
34443 "beforeload" : true,
34446 * Fires when a node is loaded
34447 * @param {Node} node The node that was loaded
34451 * @event textchange
34452 * Fires when the text for a node is changed
34453 * @param {Node} node The node
34454 * @param {String} text The new text
34455 * @param {String} oldText The old text
34457 "textchange" : true,
34459 * @event beforeexpand
34460 * Fires before a node is expanded, return false to cancel.
34461 * @param {Node} node The node
34462 * @param {Boolean} deep
34463 * @param {Boolean} anim
34465 "beforeexpand" : true,
34467 * @event beforecollapse
34468 * Fires before a node is collapsed, return false to cancel.
34469 * @param {Node} node The node
34470 * @param {Boolean} deep
34471 * @param {Boolean} anim
34473 "beforecollapse" : true,
34476 * Fires when a node is expanded
34477 * @param {Node} node The node
34481 * @event disabledchange
34482 * Fires when the disabled status of a node changes
34483 * @param {Node} node The node
34484 * @param {Boolean} disabled
34486 "disabledchange" : true,
34489 * Fires when a node is collapsed
34490 * @param {Node} node The node
34494 * @event beforeclick
34495 * Fires before click processing on a node. Return false to cancel the default action.
34496 * @param {Node} node The node
34497 * @param {Roo.EventObject} e The event object
34499 "beforeclick":true,
34501 * @event checkchange
34502 * Fires when a node with a checkbox's checked property changes
34503 * @param {Node} this This node
34504 * @param {Boolean} checked
34506 "checkchange":true,
34509 * Fires when a node is clicked
34510 * @param {Node} node The node
34511 * @param {Roo.EventObject} e The event object
34516 * Fires when a node is double clicked
34517 * @param {Node} node The node
34518 * @param {Roo.EventObject} e The event object
34522 * @event contextmenu
34523 * Fires when a node is right clicked
34524 * @param {Node} node The node
34525 * @param {Roo.EventObject} e The event object
34527 "contextmenu":true,
34529 * @event beforechildrenrendered
34530 * Fires right before the child nodes for a node are rendered
34531 * @param {Node} node The node
34533 "beforechildrenrendered":true,
34536 * Fires when a node starts being dragged
34537 * @param {Roo.tree.TreePanel} this
34538 * @param {Roo.tree.TreeNode} node
34539 * @param {event} e The raw browser event
34541 "startdrag" : true,
34544 * Fires when a drag operation is complete
34545 * @param {Roo.tree.TreePanel} this
34546 * @param {Roo.tree.TreeNode} node
34547 * @param {event} e The raw browser event
34552 * Fires when a dragged node is dropped on a valid DD target
34553 * @param {Roo.tree.TreePanel} this
34554 * @param {Roo.tree.TreeNode} node
34555 * @param {DD} dd The dd it was dropped on
34556 * @param {event} e The raw browser event
34560 * @event beforenodedrop
34561 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
34562 * passed to handlers has the following properties:<br />
34563 * <ul style="padding:5px;padding-left:16px;">
34564 * <li>tree - The TreePanel</li>
34565 * <li>target - The node being targeted for the drop</li>
34566 * <li>data - The drag data from the drag source</li>
34567 * <li>point - The point of the drop - append, above or below</li>
34568 * <li>source - The drag source</li>
34569 * <li>rawEvent - Raw mouse event</li>
34570 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
34571 * to be inserted by setting them on this object.</li>
34572 * <li>cancel - Set this to true to cancel the drop.</li>
34574 * @param {Object} dropEvent
34576 "beforenodedrop" : true,
34579 * Fires after a DD object is dropped on a node in this tree. The dropEvent
34580 * passed to handlers has the following properties:<br />
34581 * <ul style="padding:5px;padding-left:16px;">
34582 * <li>tree - The TreePanel</li>
34583 * <li>target - The node being targeted for the drop</li>
34584 * <li>data - The drag data from the drag source</li>
34585 * <li>point - The point of the drop - append, above or below</li>
34586 * <li>source - The drag source</li>
34587 * <li>rawEvent - Raw mouse event</li>
34588 * <li>dropNode - Dropped node(s).</li>
34590 * @param {Object} dropEvent
34594 * @event nodedragover
34595 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
34596 * passed to handlers has the following properties:<br />
34597 * <ul style="padding:5px;padding-left:16px;">
34598 * <li>tree - The TreePanel</li>
34599 * <li>target - The node being targeted for the drop</li>
34600 * <li>data - The drag data from the drag source</li>
34601 * <li>point - The point of the drop - append, above or below</li>
34602 * <li>source - The drag source</li>
34603 * <li>rawEvent - Raw mouse event</li>
34604 * <li>dropNode - Drop node(s) provided by the source.</li>
34605 * <li>cancel - Set this to true to signal drop not allowed.</li>
34607 * @param {Object} dragOverEvent
34609 "nodedragover" : true,
34611 * @event appendnode
34612 * Fires when append node to the tree
34613 * @param {Roo.tree.TreePanel} this
34614 * @param {Roo.tree.TreeNode} node
34615 * @param {Number} index The index of the newly appended node
34617 "appendnode" : true
34620 if(this.singleExpand){
34621 this.on("beforeexpand", this.restrictExpand, this);
34624 this.editor.tree = this;
34625 this.editor = Roo.factory(this.editor, Roo.tree);
34628 if (this.selModel) {
34629 this.selModel = Roo.factory(this.selModel, Roo.tree);
34633 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
34634 rootVisible : true,
34635 animate: Roo.enableFx,
34638 hlDrop : Roo.enableFx,
34642 rendererTip: false,
34644 restrictExpand : function(node){
34645 var p = node.parentNode;
34647 if(p.expandedChild && p.expandedChild.parentNode == p){
34648 p.expandedChild.collapse();
34650 p.expandedChild = node;
34654 // private override
34655 setRootNode : function(node){
34656 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
34657 if(!this.rootVisible){
34658 node.ui = new Roo.tree.RootTreeNodeUI(node);
34664 * Returns the container element for this TreePanel
34666 getEl : function(){
34671 * Returns the default TreeLoader for this TreePanel
34673 getLoader : function(){
34674 return this.loader;
34680 expandAll : function(){
34681 this.root.expand(true);
34685 * Collapse all nodes
34687 collapseAll : function(){
34688 this.root.collapse(true);
34692 * Returns the selection model used by this TreePanel
34694 getSelectionModel : function(){
34695 if(!this.selModel){
34696 this.selModel = new Roo.tree.DefaultSelectionModel();
34698 return this.selModel;
34702 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
34703 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
34704 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
34707 getChecked : function(a, startNode){
34708 startNode = startNode || this.root;
34710 var f = function(){
34711 if(this.attributes.checked){
34712 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
34715 startNode.cascade(f);
34720 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
34721 * @param {String} path
34722 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
34723 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
34724 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
34726 expandPath : function(path, attr, callback){
34727 attr = attr || "id";
34728 var keys = path.split(this.pathSeparator);
34729 var curNode = this.root;
34730 if(curNode.attributes[attr] != keys[1]){ // invalid root
34732 callback(false, null);
34737 var f = function(){
34738 if(++index == keys.length){
34740 callback(true, curNode);
34744 var c = curNode.findChild(attr, keys[index]);
34747 callback(false, curNode);
34752 c.expand(false, false, f);
34754 curNode.expand(false, false, f);
34758 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
34759 * @param {String} path
34760 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
34761 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
34762 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
34764 selectPath : function(path, attr, callback){
34765 attr = attr || "id";
34766 var keys = path.split(this.pathSeparator);
34767 var v = keys.pop();
34768 if(keys.length > 0){
34769 var f = function(success, node){
34770 if(success && node){
34771 var n = node.findChild(attr, v);
34777 }else if(callback){
34778 callback(false, n);
34782 callback(false, n);
34786 this.expandPath(keys.join(this.pathSeparator), attr, f);
34788 this.root.select();
34790 callback(true, this.root);
34795 getTreeEl : function(){
34800 * Trigger rendering of this TreePanel
34802 render : function(){
34803 if (this.innerCt) {
34804 return this; // stop it rendering more than once!!
34807 this.innerCt = this.el.createChild({tag:"ul",
34808 cls:"x-tree-root-ct " +
34809 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
34811 if(this.containerScroll){
34812 Roo.dd.ScrollManager.register(this.el);
34814 if((this.enableDD || this.enableDrop) && !this.dropZone){
34816 * The dropZone used by this tree if drop is enabled
34817 * @type Roo.tree.TreeDropZone
34819 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
34820 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
34823 if((this.enableDD || this.enableDrag) && !this.dragZone){
34825 * The dragZone used by this tree if drag is enabled
34826 * @type Roo.tree.TreeDragZone
34828 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
34829 ddGroup: this.ddGroup || "TreeDD",
34830 scroll: this.ddScroll
34833 this.getSelectionModel().init(this);
34835 Roo.log("ROOT not set in tree");
34838 this.root.render();
34839 if(!this.rootVisible){
34840 this.root.renderChildren();
34846 * Ext JS Library 1.1.1
34847 * Copyright(c) 2006-2007, Ext JS, LLC.
34849 * Originally Released Under LGPL - original licence link has changed is not relivant.
34852 * <script type="text/javascript">
34857 * @class Roo.tree.DefaultSelectionModel
34858 * @extends Roo.util.Observable
34859 * The default single selection for a TreePanel.
34860 * @param {Object} cfg Configuration
34862 Roo.tree.DefaultSelectionModel = function(cfg){
34863 this.selNode = null;
34869 * @event selectionchange
34870 * Fires when the selected node changes
34871 * @param {DefaultSelectionModel} this
34872 * @param {TreeNode} node the new selection
34874 "selectionchange" : true,
34877 * @event beforeselect
34878 * Fires before the selected node changes, return false to cancel the change
34879 * @param {DefaultSelectionModel} this
34880 * @param {TreeNode} node the new selection
34881 * @param {TreeNode} node the old selection
34883 "beforeselect" : true
34886 Roo.tree.DefaultSelectionModel.superclass.constructor.call(this,cfg);
34889 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
34890 init : function(tree){
34892 tree.getTreeEl().on("keydown", this.onKeyDown, this);
34893 tree.on("click", this.onNodeClick, this);
34896 onNodeClick : function(node, e){
34897 if (e.ctrlKey && this.selNode == node) {
34898 this.unselect(node);
34906 * @param {TreeNode} node The node to select
34907 * @return {TreeNode} The selected node
34909 select : function(node){
34910 var last = this.selNode;
34911 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
34913 last.ui.onSelectedChange(false);
34915 this.selNode = node;
34916 node.ui.onSelectedChange(true);
34917 this.fireEvent("selectionchange", this, node, last);
34924 * @param {TreeNode} node The node to unselect
34926 unselect : function(node){
34927 if(this.selNode == node){
34928 this.clearSelections();
34933 * Clear all selections
34935 clearSelections : function(){
34936 var n = this.selNode;
34938 n.ui.onSelectedChange(false);
34939 this.selNode = null;
34940 this.fireEvent("selectionchange", this, null);
34946 * Get the selected node
34947 * @return {TreeNode} The selected node
34949 getSelectedNode : function(){
34950 return this.selNode;
34954 * Returns true if the node is selected
34955 * @param {TreeNode} node The node to check
34956 * @return {Boolean}
34958 isSelected : function(node){
34959 return this.selNode == node;
34963 * Selects the node above the selected node in the tree, intelligently walking the nodes
34964 * @return TreeNode The new selection
34966 selectPrevious : function(){
34967 var s = this.selNode || this.lastSelNode;
34971 var ps = s.previousSibling;
34973 if(!ps.isExpanded() || ps.childNodes.length < 1){
34974 return this.select(ps);
34976 var lc = ps.lastChild;
34977 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
34980 return this.select(lc);
34982 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
34983 return this.select(s.parentNode);
34989 * Selects the node above the selected node in the tree, intelligently walking the nodes
34990 * @return TreeNode The new selection
34992 selectNext : function(){
34993 var s = this.selNode || this.lastSelNode;
34997 if(s.firstChild && s.isExpanded()){
34998 return this.select(s.firstChild);
34999 }else if(s.nextSibling){
35000 return this.select(s.nextSibling);
35001 }else if(s.parentNode){
35003 s.parentNode.bubble(function(){
35004 if(this.nextSibling){
35005 newS = this.getOwnerTree().selModel.select(this.nextSibling);
35014 onKeyDown : function(e){
35015 var s = this.selNode || this.lastSelNode;
35016 // undesirable, but required
35021 var k = e.getKey();
35029 this.selectPrevious();
35032 e.preventDefault();
35033 if(s.hasChildNodes()){
35034 if(!s.isExpanded()){
35036 }else if(s.firstChild){
35037 this.select(s.firstChild, e);
35042 e.preventDefault();
35043 if(s.hasChildNodes() && s.isExpanded()){
35045 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
35046 this.select(s.parentNode, e);
35054 * @class Roo.tree.MultiSelectionModel
35055 * @extends Roo.util.Observable
35056 * Multi selection for a TreePanel.
35057 * @param {Object} cfg Configuration
35059 Roo.tree.MultiSelectionModel = function(){
35060 this.selNodes = [];
35064 * @event selectionchange
35065 * Fires when the selected nodes change
35066 * @param {MultiSelectionModel} this
35067 * @param {Array} nodes Array of the selected nodes
35069 "selectionchange" : true
35071 Roo.tree.MultiSelectionModel.superclass.constructor.call(this,cfg);
35075 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
35076 init : function(tree){
35078 tree.getTreeEl().on("keydown", this.onKeyDown, this);
35079 tree.on("click", this.onNodeClick, this);
35082 onNodeClick : function(node, e){
35083 this.select(node, e, e.ctrlKey);
35088 * @param {TreeNode} node The node to select
35089 * @param {EventObject} e (optional) An event associated with the selection
35090 * @param {Boolean} keepExisting True to retain existing selections
35091 * @return {TreeNode} The selected node
35093 select : function(node, e, keepExisting){
35094 if(keepExisting !== true){
35095 this.clearSelections(true);
35097 if(this.isSelected(node)){
35098 this.lastSelNode = node;
35101 this.selNodes.push(node);
35102 this.selMap[node.id] = node;
35103 this.lastSelNode = node;
35104 node.ui.onSelectedChange(true);
35105 this.fireEvent("selectionchange", this, this.selNodes);
35111 * @param {TreeNode} node The node to unselect
35113 unselect : function(node){
35114 if(this.selMap[node.id]){
35115 node.ui.onSelectedChange(false);
35116 var sn = this.selNodes;
35119 index = sn.indexOf(node);
35121 for(var i = 0, len = sn.length; i < len; i++){
35129 this.selNodes.splice(index, 1);
35131 delete this.selMap[node.id];
35132 this.fireEvent("selectionchange", this, this.selNodes);
35137 * Clear all selections
35139 clearSelections : function(suppressEvent){
35140 var sn = this.selNodes;
35142 for(var i = 0, len = sn.length; i < len; i++){
35143 sn[i].ui.onSelectedChange(false);
35145 this.selNodes = [];
35147 if(suppressEvent !== true){
35148 this.fireEvent("selectionchange", this, this.selNodes);
35154 * Returns true if the node is selected
35155 * @param {TreeNode} node The node to check
35156 * @return {Boolean}
35158 isSelected : function(node){
35159 return this.selMap[node.id] ? true : false;
35163 * Returns an array of the selected nodes
35166 getSelectedNodes : function(){
35167 return this.selNodes;
35170 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
35172 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
35174 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
35177 * Ext JS Library 1.1.1
35178 * Copyright(c) 2006-2007, Ext JS, LLC.
35180 * Originally Released Under LGPL - original licence link has changed is not relivant.
35183 * <script type="text/javascript">
35187 * @class Roo.tree.TreeNode
35188 * @extends Roo.data.Node
35189 * @cfg {String} text The text for this node
35190 * @cfg {Boolean} expanded true to start the node expanded
35191 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
35192 * @cfg {Boolean} allowDrop false if this node cannot be drop on
35193 * @cfg {Boolean} disabled true to start the node disabled
35194 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
35195 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
35196 * @cfg {String} cls A css class to be added to the node
35197 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
35198 * @cfg {String} href URL of the link used for the node (defaults to #)
35199 * @cfg {String} hrefTarget target frame for the link
35200 * @cfg {String} qtip An Ext QuickTip for the node
35201 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
35202 * @cfg {Boolean} singleClickExpand True for single click expand on this node
35203 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
35204 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
35205 * (defaults to undefined with no checkbox rendered)
35207 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
35209 Roo.tree.TreeNode = function(attributes){
35210 attributes = attributes || {};
35211 if(typeof attributes == "string"){
35212 attributes = {text: attributes};
35214 this.childrenRendered = false;
35215 this.rendered = false;
35216 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
35217 this.expanded = attributes.expanded === true;
35218 this.isTarget = attributes.isTarget !== false;
35219 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
35220 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
35223 * Read-only. The text for this node. To change it use setText().
35226 this.text = attributes.text;
35228 * True if this node is disabled.
35231 this.disabled = attributes.disabled === true;
35235 * @event textchange
35236 * Fires when the text for this node is changed
35237 * @param {Node} this This node
35238 * @param {String} text The new text
35239 * @param {String} oldText The old text
35241 "textchange" : true,
35243 * @event beforeexpand
35244 * Fires before this node is expanded, return false to cancel.
35245 * @param {Node} this This node
35246 * @param {Boolean} deep
35247 * @param {Boolean} anim
35249 "beforeexpand" : true,
35251 * @event beforecollapse
35252 * Fires before this node is collapsed, return false to cancel.
35253 * @param {Node} this This node
35254 * @param {Boolean} deep
35255 * @param {Boolean} anim
35257 "beforecollapse" : true,
35260 * Fires when this node is expanded
35261 * @param {Node} this This node
35265 * @event disabledchange
35266 * Fires when the disabled status of this node changes
35267 * @param {Node} this This node
35268 * @param {Boolean} disabled
35270 "disabledchange" : true,
35273 * Fires when this node is collapsed
35274 * @param {Node} this This node
35278 * @event beforeclick
35279 * Fires before click processing. Return false to cancel the default action.
35280 * @param {Node} this This node
35281 * @param {Roo.EventObject} e The event object
35283 "beforeclick":true,
35285 * @event checkchange
35286 * Fires when a node with a checkbox's checked property changes
35287 * @param {Node} this This node
35288 * @param {Boolean} checked
35290 "checkchange":true,
35293 * Fires when this node is clicked
35294 * @param {Node} this This node
35295 * @param {Roo.EventObject} e The event object
35300 * Fires when this node is double clicked
35301 * @param {Node} this This node
35302 * @param {Roo.EventObject} e The event object
35306 * @event contextmenu
35307 * Fires when this node is right clicked
35308 * @param {Node} this This node
35309 * @param {Roo.EventObject} e The event object
35311 "contextmenu":true,
35313 * @event beforechildrenrendered
35314 * Fires right before the child nodes for this node are rendered
35315 * @param {Node} this This node
35317 "beforechildrenrendered":true
35320 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
35323 * Read-only. The UI for this node
35326 this.ui = new uiClass(this);
35328 // finally support items[]
35329 if (typeof(this.attributes.items) == 'undefined' || !this.attributes.items) {
35334 Roo.each(this.attributes.items, function(c) {
35335 this.appendChild(Roo.factory(c,Roo.Tree));
35337 delete this.attributes.items;
35342 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
35343 preventHScroll: true,
35345 * Returns true if this node is expanded
35346 * @return {Boolean}
35348 isExpanded : function(){
35349 return this.expanded;
35353 * Returns the UI object for this node
35354 * @return {TreeNodeUI}
35356 getUI : function(){
35360 // private override
35361 setFirstChild : function(node){
35362 var of = this.firstChild;
35363 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
35364 if(this.childrenRendered && of && node != of){
35365 of.renderIndent(true, true);
35368 this.renderIndent(true, true);
35372 // private override
35373 setLastChild : function(node){
35374 var ol = this.lastChild;
35375 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
35376 if(this.childrenRendered && ol && node != ol){
35377 ol.renderIndent(true, true);
35380 this.renderIndent(true, true);
35384 // these methods are overridden to provide lazy rendering support
35385 // private override
35386 appendChild : function()
35388 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
35389 if(node && this.childrenRendered){
35392 this.ui.updateExpandIcon();
35396 // private override
35397 removeChild : function(node){
35398 this.ownerTree.getSelectionModel().unselect(node);
35399 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
35400 // if it's been rendered remove dom node
35401 if(this.childrenRendered){
35404 if(this.childNodes.length < 1){
35405 this.collapse(false, false);
35407 this.ui.updateExpandIcon();
35409 if(!this.firstChild) {
35410 this.childrenRendered = false;
35415 // private override
35416 insertBefore : function(node, refNode){
35417 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
35418 if(newNode && refNode && this.childrenRendered){
35421 this.ui.updateExpandIcon();
35426 * Sets the text for this node
35427 * @param {String} text
35429 setText : function(text){
35430 var oldText = this.text;
35432 this.attributes.text = text;
35433 if(this.rendered){ // event without subscribing
35434 this.ui.onTextChange(this, text, oldText);
35436 this.fireEvent("textchange", this, text, oldText);
35440 * Triggers selection of this node
35442 select : function(){
35443 this.getOwnerTree().getSelectionModel().select(this);
35447 * Triggers deselection of this node
35449 unselect : function(){
35450 this.getOwnerTree().getSelectionModel().unselect(this);
35454 * Returns true if this node is selected
35455 * @return {Boolean}
35457 isSelected : function(){
35458 return this.getOwnerTree().getSelectionModel().isSelected(this);
35462 * Expand this node.
35463 * @param {Boolean} deep (optional) True to expand all children as well
35464 * @param {Boolean} anim (optional) false to cancel the default animation
35465 * @param {Function} callback (optional) A callback to be called when
35466 * expanding this node completes (does not wait for deep expand to complete).
35467 * Called with 1 parameter, this node.
35469 expand : function(deep, anim, callback){
35470 if(!this.expanded){
35471 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
35474 if(!this.childrenRendered){
35475 this.renderChildren();
35477 this.expanded = true;
35479 if(!this.isHiddenRoot() && (this.getOwnerTree() && this.getOwnerTree().animate && anim !== false) || anim){
35480 this.ui.animExpand(function(){
35481 this.fireEvent("expand", this);
35482 if(typeof callback == "function"){
35486 this.expandChildNodes(true);
35488 }.createDelegate(this));
35492 this.fireEvent("expand", this);
35493 if(typeof callback == "function"){
35498 if(typeof callback == "function"){
35503 this.expandChildNodes(true);
35507 isHiddenRoot : function(){
35508 return this.isRoot && !this.getOwnerTree().rootVisible;
35512 * Collapse this node.
35513 * @param {Boolean} deep (optional) True to collapse all children as well
35514 * @param {Boolean} anim (optional) false to cancel the default animation
35516 collapse : function(deep, anim){
35517 if(this.expanded && !this.isHiddenRoot()){
35518 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
35521 this.expanded = false;
35522 if((this.getOwnerTree().animate && anim !== false) || anim){
35523 this.ui.animCollapse(function(){
35524 this.fireEvent("collapse", this);
35526 this.collapseChildNodes(true);
35528 }.createDelegate(this));
35531 this.ui.collapse();
35532 this.fireEvent("collapse", this);
35536 var cs = this.childNodes;
35537 for(var i = 0, len = cs.length; i < len; i++) {
35538 cs[i].collapse(true, false);
35544 delayedExpand : function(delay){
35545 if(!this.expandProcId){
35546 this.expandProcId = this.expand.defer(delay, this);
35551 cancelExpand : function(){
35552 if(this.expandProcId){
35553 clearTimeout(this.expandProcId);
35555 this.expandProcId = false;
35559 * Toggles expanded/collapsed state of the node
35561 toggle : function(){
35570 * Ensures all parent nodes are expanded
35572 ensureVisible : function(callback){
35573 var tree = this.getOwnerTree();
35574 tree.expandPath(this.parentNode.getPath(), false, function(){
35575 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
35576 Roo.callback(callback);
35577 }.createDelegate(this));
35581 * Expand all child nodes
35582 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
35584 expandChildNodes : function(deep){
35585 var cs = this.childNodes;
35586 for(var i = 0, len = cs.length; i < len; i++) {
35587 cs[i].expand(deep);
35592 * Collapse all child nodes
35593 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
35595 collapseChildNodes : function(deep){
35596 var cs = this.childNodes;
35597 for(var i = 0, len = cs.length; i < len; i++) {
35598 cs[i].collapse(deep);
35603 * Disables this node
35605 disable : function(){
35606 this.disabled = true;
35608 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
35609 this.ui.onDisableChange(this, true);
35611 this.fireEvent("disabledchange", this, true);
35615 * Enables this node
35617 enable : function(){
35618 this.disabled = false;
35619 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
35620 this.ui.onDisableChange(this, false);
35622 this.fireEvent("disabledchange", this, false);
35626 renderChildren : function(suppressEvent){
35627 if(suppressEvent !== false){
35628 this.fireEvent("beforechildrenrendered", this);
35630 var cs = this.childNodes;
35631 for(var i = 0, len = cs.length; i < len; i++){
35632 cs[i].render(true);
35634 this.childrenRendered = true;
35638 sort : function(fn, scope){
35639 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
35640 if(this.childrenRendered){
35641 var cs = this.childNodes;
35642 for(var i = 0, len = cs.length; i < len; i++){
35643 cs[i].render(true);
35649 render : function(bulkRender){
35650 this.ui.render(bulkRender);
35651 if(!this.rendered){
35652 this.rendered = true;
35654 this.expanded = false;
35655 this.expand(false, false);
35661 renderIndent : function(deep, refresh){
35663 this.ui.childIndent = null;
35665 this.ui.renderIndent();
35666 if(deep === true && this.childrenRendered){
35667 var cs = this.childNodes;
35668 for(var i = 0, len = cs.length; i < len; i++){
35669 cs[i].renderIndent(true, refresh);
35675 * Ext JS Library 1.1.1
35676 * Copyright(c) 2006-2007, Ext JS, LLC.
35678 * Originally Released Under LGPL - original licence link has changed is not relivant.
35681 * <script type="text/javascript">
35685 * @class Roo.tree.AsyncTreeNode
35686 * @extends Roo.tree.TreeNode
35687 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
35689 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
35691 Roo.tree.AsyncTreeNode = function(config){
35692 this.loaded = false;
35693 this.loading = false;
35694 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
35696 * @event beforeload
35697 * Fires before this node is loaded, return false to cancel
35698 * @param {Node} this This node
35700 this.addEvents({'beforeload':true, 'load': true});
35703 * Fires when this node is loaded
35704 * @param {Node} this This node
35707 * The loader used by this node (defaults to using the tree's defined loader)
35712 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
35713 expand : function(deep, anim, callback){
35714 if(this.loading){ // if an async load is already running, waiting til it's done
35716 var f = function(){
35717 if(!this.loading){ // done loading
35718 clearInterval(timer);
35719 this.expand(deep, anim, callback);
35721 }.createDelegate(this);
35722 timer = setInterval(f, 200);
35726 if(this.fireEvent("beforeload", this) === false){
35729 this.loading = true;
35730 this.ui.beforeLoad(this);
35731 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
35733 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
35737 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
35741 * Returns true if this node is currently loading
35742 * @return {Boolean}
35744 isLoading : function(){
35745 return this.loading;
35748 loadComplete : function(deep, anim, callback){
35749 this.loading = false;
35750 this.loaded = true;
35751 this.ui.afterLoad(this);
35752 this.fireEvent("load", this);
35753 this.expand(deep, anim, callback);
35757 * Returns true if this node has been loaded
35758 * @return {Boolean}
35760 isLoaded : function(){
35761 return this.loaded;
35764 hasChildNodes : function(){
35765 if(!this.isLeaf() && !this.loaded){
35768 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
35773 * Trigger a reload for this node
35774 * @param {Function} callback
35776 reload : function(callback){
35777 this.collapse(false, false);
35778 while(this.firstChild){
35779 this.removeChild(this.firstChild);
35781 this.childrenRendered = false;
35782 this.loaded = false;
35783 if(this.isHiddenRoot()){
35784 this.expanded = false;
35786 this.expand(false, false, callback);
35790 * Ext JS Library 1.1.1
35791 * Copyright(c) 2006-2007, Ext JS, LLC.
35793 * Originally Released Under LGPL - original licence link has changed is not relivant.
35796 * <script type="text/javascript">
35800 * @class Roo.tree.TreeNodeUI
35802 * @param {Object} node The node to render
35803 * The TreeNode UI implementation is separate from the
35804 * tree implementation. Unless you are customizing the tree UI,
35805 * you should never have to use this directly.
35807 Roo.tree.TreeNodeUI = function(node){
35809 this.rendered = false;
35810 this.animating = false;
35811 this.emptyIcon = Roo.BLANK_IMAGE_URL;
35814 Roo.tree.TreeNodeUI.prototype = {
35815 removeChild : function(node){
35817 this.ctNode.removeChild(node.ui.getEl());
35821 beforeLoad : function(){
35822 this.addClass("x-tree-node-loading");
35825 afterLoad : function(){
35826 this.removeClass("x-tree-node-loading");
35829 onTextChange : function(node, text, oldText){
35831 this.textNode.innerHTML = text;
35835 onDisableChange : function(node, state){
35836 this.disabled = state;
35838 this.addClass("x-tree-node-disabled");
35840 this.removeClass("x-tree-node-disabled");
35844 onSelectedChange : function(state){
35847 this.addClass("x-tree-selected");
35850 this.removeClass("x-tree-selected");
35854 onMove : function(tree, node, oldParent, newParent, index, refNode){
35855 this.childIndent = null;
35857 var targetNode = newParent.ui.getContainer();
35858 if(!targetNode){//target not rendered
35859 this.holder = document.createElement("div");
35860 this.holder.appendChild(this.wrap);
35863 var insertBefore = refNode ? refNode.ui.getEl() : null;
35865 targetNode.insertBefore(this.wrap, insertBefore);
35867 targetNode.appendChild(this.wrap);
35869 this.node.renderIndent(true);
35873 addClass : function(cls){
35875 Roo.fly(this.elNode).addClass(cls);
35879 removeClass : function(cls){
35881 Roo.fly(this.elNode).removeClass(cls);
35885 remove : function(){
35887 this.holder = document.createElement("div");
35888 this.holder.appendChild(this.wrap);
35892 fireEvent : function(){
35893 return this.node.fireEvent.apply(this.node, arguments);
35896 initEvents : function(){
35897 this.node.on("move", this.onMove, this);
35898 var E = Roo.EventManager;
35899 var a = this.anchor;
35901 var el = Roo.fly(a, '_treeui');
35903 if(Roo.isOpera){ // opera render bug ignores the CSS
35904 el.setStyle("text-decoration", "none");
35907 el.on("click", this.onClick, this);
35908 el.on("dblclick", this.onDblClick, this);
35911 Roo.EventManager.on(this.checkbox,
35912 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
35915 el.on("contextmenu", this.onContextMenu, this);
35917 var icon = Roo.fly(this.iconNode);
35918 icon.on("click", this.onClick, this);
35919 icon.on("dblclick", this.onDblClick, this);
35920 icon.on("contextmenu", this.onContextMenu, this);
35921 E.on(this.ecNode, "click", this.ecClick, this, true);
35923 if(this.node.disabled){
35924 this.addClass("x-tree-node-disabled");
35926 if(this.node.hidden){
35927 this.addClass("x-tree-node-disabled");
35929 var ot = this.node.getOwnerTree();
35930 var dd = ot ? (ot.enableDD || ot.enableDrag || ot.enableDrop) : false;
35931 if(dd && (!this.node.isRoot || ot.rootVisible)){
35932 Roo.dd.Registry.register(this.elNode, {
35934 handles: this.getDDHandles(),
35940 getDDHandles : function(){
35941 return [this.iconNode, this.textNode];
35946 this.wrap.style.display = "none";
35952 this.wrap.style.display = "";
35956 onContextMenu : function(e){
35957 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
35958 e.preventDefault();
35960 this.fireEvent("contextmenu", this.node, e);
35964 onClick : function(e){
35969 if(this.fireEvent("beforeclick", this.node, e) !== false){
35970 if(!this.disabled && this.node.attributes.href){
35971 this.fireEvent("click", this.node, e);
35974 e.preventDefault();
35979 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
35980 this.node.toggle();
35983 this.fireEvent("click", this.node, e);
35989 onDblClick : function(e){
35990 e.preventDefault();
35995 this.toggleCheck();
35997 if(!this.animating && this.node.hasChildNodes()){
35998 this.node.toggle();
36000 this.fireEvent("dblclick", this.node, e);
36003 onCheckChange : function(){
36004 var checked = this.checkbox.checked;
36005 this.node.attributes.checked = checked;
36006 this.fireEvent('checkchange', this.node, checked);
36009 ecClick : function(e){
36010 if(!this.animating && this.node.hasChildNodes()){
36011 this.node.toggle();
36015 startDrop : function(){
36016 this.dropping = true;
36019 // delayed drop so the click event doesn't get fired on a drop
36020 endDrop : function(){
36021 setTimeout(function(){
36022 this.dropping = false;
36023 }.createDelegate(this), 50);
36026 expand : function(){
36027 this.updateExpandIcon();
36028 this.ctNode.style.display = "";
36031 focus : function(){
36032 if(!this.node.preventHScroll){
36033 try{this.anchor.focus();
36035 }else if(!Roo.isIE){
36037 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
36038 var l = noscroll.scrollLeft;
36039 this.anchor.focus();
36040 noscroll.scrollLeft = l;
36045 toggleCheck : function(value){
36046 var cb = this.checkbox;
36048 cb.checked = (value === undefined ? !cb.checked : value);
36054 this.anchor.blur();
36058 animExpand : function(callback){
36059 var ct = Roo.get(this.ctNode);
36061 if(!this.node.hasChildNodes()){
36062 this.updateExpandIcon();
36063 this.ctNode.style.display = "";
36064 Roo.callback(callback);
36067 this.animating = true;
36068 this.updateExpandIcon();
36071 callback : function(){
36072 this.animating = false;
36073 Roo.callback(callback);
36076 duration: this.node.ownerTree.duration || .25
36080 highlight : function(){
36081 var tree = this.node.getOwnerTree();
36082 Roo.fly(this.wrap).highlight(
36083 tree.hlColor || "C3DAF9",
36084 {endColor: tree.hlBaseColor}
36088 collapse : function(){
36089 this.updateExpandIcon();
36090 this.ctNode.style.display = "none";
36093 animCollapse : function(callback){
36094 var ct = Roo.get(this.ctNode);
36095 ct.enableDisplayMode('block');
36098 this.animating = true;
36099 this.updateExpandIcon();
36102 callback : function(){
36103 this.animating = false;
36104 Roo.callback(callback);
36107 duration: this.node.ownerTree.duration || .25
36111 getContainer : function(){
36112 return this.ctNode;
36115 getEl : function(){
36119 appendDDGhost : function(ghostNode){
36120 ghostNode.appendChild(this.elNode.cloneNode(true));
36123 getDDRepairXY : function(){
36124 return Roo.lib.Dom.getXY(this.iconNode);
36127 onRender : function(){
36131 render : function(bulkRender){
36132 var n = this.node, a = n.attributes;
36133 var targetNode = n.parentNode ?
36134 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
36136 if(!this.rendered){
36137 this.rendered = true;
36139 this.renderElements(n, a, targetNode, bulkRender);
36142 if(this.textNode.setAttributeNS){
36143 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
36145 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
36148 this.textNode.setAttribute("ext:qtip", a.qtip);
36150 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
36153 }else if(a.qtipCfg){
36154 a.qtipCfg.target = Roo.id(this.textNode);
36155 Roo.QuickTips.register(a.qtipCfg);
36158 if(!this.node.expanded){
36159 this.updateExpandIcon();
36162 if(bulkRender === true) {
36163 targetNode.appendChild(this.wrap);
36168 renderElements : function(n, a, targetNode, bulkRender)
36170 // add some indent caching, this helps performance when rendering a large tree
36171 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
36172 var t = n.getOwnerTree();
36173 var txt = t && t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
36174 if (typeof(n.attributes.html) != 'undefined') {
36175 txt = n.attributes.html;
36177 var tip = t && t.rendererTip ? t.rendererTip(n.attributes) : txt;
36178 var cb = typeof a.checked == 'boolean';
36179 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
36180 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
36181 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
36182 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
36183 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
36184 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
36185 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
36186 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
36187 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
36188 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
36191 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
36192 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
36193 n.nextSibling.ui.getEl(), buf.join(""));
36195 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
36198 this.elNode = this.wrap.childNodes[0];
36199 this.ctNode = this.wrap.childNodes[1];
36200 var cs = this.elNode.childNodes;
36201 this.indentNode = cs[0];
36202 this.ecNode = cs[1];
36203 this.iconNode = cs[2];
36206 this.checkbox = cs[3];
36209 this.anchor = cs[index];
36210 this.textNode = cs[index].firstChild;
36213 getAnchor : function(){
36214 return this.anchor;
36217 getTextEl : function(){
36218 return this.textNode;
36221 getIconEl : function(){
36222 return this.iconNode;
36225 isChecked : function(){
36226 return this.checkbox ? this.checkbox.checked : false;
36229 updateExpandIcon : function(){
36231 var n = this.node, c1, c2;
36232 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
36233 var hasChild = n.hasChildNodes();
36237 c1 = "x-tree-node-collapsed";
36238 c2 = "x-tree-node-expanded";
36241 c1 = "x-tree-node-expanded";
36242 c2 = "x-tree-node-collapsed";
36245 this.removeClass("x-tree-node-leaf");
36246 this.wasLeaf = false;
36248 if(this.c1 != c1 || this.c2 != c2){
36249 Roo.fly(this.elNode).replaceClass(c1, c2);
36250 this.c1 = c1; this.c2 = c2;
36253 // this changes non-leafs into leafs if they have no children.
36254 // it's not very rational behaviour..
36256 if(!this.wasLeaf && this.node.leaf){
36257 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
36260 this.wasLeaf = true;
36263 var ecc = "x-tree-ec-icon "+cls;
36264 if(this.ecc != ecc){
36265 this.ecNode.className = ecc;
36271 getChildIndent : function(){
36272 if(!this.childIndent){
36276 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
36278 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
36280 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
36285 this.childIndent = buf.join("");
36287 return this.childIndent;
36290 renderIndent : function(){
36293 var p = this.node.parentNode;
36295 indent = p.ui.getChildIndent();
36297 if(this.indentMarkup != indent){ // don't rerender if not required
36298 this.indentNode.innerHTML = indent;
36299 this.indentMarkup = indent;
36301 this.updateExpandIcon();
36306 Roo.tree.RootTreeNodeUI = function(){
36307 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
36309 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
36310 render : function(){
36311 if(!this.rendered){
36312 var targetNode = this.node.ownerTree.innerCt.dom;
36313 this.node.expanded = true;
36314 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
36315 this.wrap = this.ctNode = targetNode.firstChild;
36318 collapse : function(){
36320 expand : function(){
36324 * Ext JS Library 1.1.1
36325 * Copyright(c) 2006-2007, Ext JS, LLC.
36327 * Originally Released Under LGPL - original licence link has changed is not relivant.
36330 * <script type="text/javascript">
36333 * @class Roo.tree.TreeLoader
36334 * @extends Roo.util.Observable
36335 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
36336 * nodes from a specified URL. The response must be a javascript Array definition
36337 * who's elements are node definition objects. eg:
36342 { 'id': 1, 'text': 'A folder Node', 'leaf': false },
36343 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }
36350 * The old style respose with just an array is still supported, but not recommended.
36353 * A server request is sent, and child nodes are loaded only when a node is expanded.
36354 * The loading node's id is passed to the server under the parameter name "node" to
36355 * enable the server to produce the correct child nodes.
36357 * To pass extra parameters, an event handler may be attached to the "beforeload"
36358 * event, and the parameters specified in the TreeLoader's baseParams property:
36360 myTreeLoader.on("beforeload", function(treeLoader, node) {
36361 this.baseParams.category = node.attributes.category;
36366 * This would pass an HTTP parameter called "category" to the server containing
36367 * the value of the Node's "category" attribute.
36369 * Creates a new Treeloader.
36370 * @param {Object} config A config object containing config properties.
36372 Roo.tree.TreeLoader = function(config){
36373 this.baseParams = {};
36374 this.requestMethod = "POST";
36375 Roo.apply(this, config);
36380 * @event beforeload
36381 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
36382 * @param {Object} This TreeLoader object.
36383 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
36384 * @param {Object} callback The callback function specified in the {@link #load} call.
36389 * Fires when the node has been successfuly loaded.
36390 * @param {Object} This TreeLoader object.
36391 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
36392 * @param {Object} response The response object containing the data from the server.
36396 * @event loadexception
36397 * Fires if the network request failed.
36398 * @param {Object} This TreeLoader object.
36399 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
36400 * @param {Object} response The response object containing the data from the server.
36402 loadexception : true,
36405 * Fires before a node is created, enabling you to return custom Node types
36406 * @param {Object} This TreeLoader object.
36407 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
36412 Roo.tree.TreeLoader.superclass.constructor.call(this);
36415 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
36417 * @cfg {String} dataUrl The URL from which to request a Json string which
36418 * specifies an array of node definition object representing the child nodes
36422 * @cfg {String} requestMethod either GET or POST
36423 * defaults to POST (due to BC)
36427 * @cfg {Object} baseParams (optional) An object containing properties which
36428 * specify HTTP parameters to be passed to each request for child nodes.
36431 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
36432 * created by this loader. If the attributes sent by the server have an attribute in this object,
36433 * they take priority.
36436 * @cfg {Object} uiProviders (optional) An object containing properties which
36438 * DEPRECATED - use 'create' event handler to modify attributes - which affect creation.
36439 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
36440 * <i>uiProvider</i> attribute of a returned child node is a string rather
36441 * than a reference to a TreeNodeUI implementation, this that string value
36442 * is used as a property name in the uiProviders object. You can define the provider named
36443 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
36448 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
36449 * child nodes before loading.
36451 clearOnLoad : true,
36454 * @cfg {String} root (optional) Default to false. Use this to read data from an object
36455 * property on loading, rather than expecting an array. (eg. more compatible to a standard
36456 * Grid query { data : [ .....] }
36461 * @cfg {String} queryParam (optional)
36462 * Name of the query as it will be passed on the querystring (defaults to 'node')
36463 * eg. the request will be ?node=[id]
36470 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
36471 * This is called automatically when a node is expanded, but may be used to reload
36472 * a node (or append new children if the {@link #clearOnLoad} option is false.)
36473 * @param {Roo.tree.TreeNode} node
36474 * @param {Function} callback
36476 load : function(node, callback){
36477 if(this.clearOnLoad){
36478 while(node.firstChild){
36479 node.removeChild(node.firstChild);
36482 if(node.attributes.children){ // preloaded json children
36483 var cs = node.attributes.children;
36484 for(var i = 0, len = cs.length; i < len; i++){
36485 node.appendChild(this.createNode(cs[i]));
36487 if(typeof callback == "function"){
36490 }else if(this.dataUrl){
36491 this.requestData(node, callback);
36495 getParams: function(node){
36496 var buf = [], bp = this.baseParams;
36497 for(var key in bp){
36498 if(typeof bp[key] != "function"){
36499 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
36502 var n = this.queryParam === false ? 'node' : this.queryParam;
36503 buf.push(n + "=", encodeURIComponent(node.id));
36504 return buf.join("");
36507 requestData : function(node, callback){
36508 if(this.fireEvent("beforeload", this, node, callback) !== false){
36509 this.transId = Roo.Ajax.request({
36510 method:this.requestMethod,
36511 url: this.dataUrl||this.url,
36512 success: this.handleResponse,
36513 failure: this.handleFailure,
36515 argument: {callback: callback, node: node},
36516 params: this.getParams(node)
36519 // if the load is cancelled, make sure we notify
36520 // the node that we are done
36521 if(typeof callback == "function"){
36527 isLoading : function(){
36528 return this.transId ? true : false;
36531 abort : function(){
36532 if(this.isLoading()){
36533 Roo.Ajax.abort(this.transId);
36538 createNode : function(attr)
36540 // apply baseAttrs, nice idea Corey!
36541 if(this.baseAttrs){
36542 Roo.applyIf(attr, this.baseAttrs);
36544 if(this.applyLoader !== false){
36545 attr.loader = this;
36547 // uiProvider = depreciated..
36549 if(typeof(attr.uiProvider) == 'string'){
36550 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
36551 /** eval:var:attr */ eval(attr.uiProvider);
36553 if(typeof(this.uiProviders['default']) != 'undefined') {
36554 attr.uiProvider = this.uiProviders['default'];
36557 this.fireEvent('create', this, attr);
36559 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
36561 new Roo.tree.TreeNode(attr) :
36562 new Roo.tree.AsyncTreeNode(attr));
36565 processResponse : function(response, node, callback)
36567 var json = response.responseText;
36570 var o = Roo.decode(json);
36572 if (this.root === false && typeof(o.success) != undefined) {
36573 this.root = 'data'; // the default behaviour for list like data..
36576 if (this.root !== false && !o.success) {
36577 // it's a failure condition.
36578 var a = response.argument;
36579 this.fireEvent("loadexception", this, a.node, response);
36580 Roo.log("Load failed - should have a handler really");
36586 if (this.root !== false) {
36590 for(var i = 0, len = o.length; i < len; i++){
36591 var n = this.createNode(o[i]);
36593 node.appendChild(n);
36596 if(typeof callback == "function"){
36597 callback(this, node);
36600 this.handleFailure(response);
36604 handleResponse : function(response){
36605 this.transId = false;
36606 var a = response.argument;
36607 this.processResponse(response, a.node, a.callback);
36608 this.fireEvent("load", this, a.node, response);
36611 handleFailure : function(response)
36613 // should handle failure better..
36614 this.transId = false;
36615 var a = response.argument;
36616 this.fireEvent("loadexception", this, a.node, response);
36617 if(typeof a.callback == "function"){
36618 a.callback(this, a.node);
36623 * Ext JS Library 1.1.1
36624 * Copyright(c) 2006-2007, Ext JS, LLC.
36626 * Originally Released Under LGPL - original licence link has changed is not relivant.
36629 * <script type="text/javascript">
36633 * @class Roo.tree.TreeFilter
36634 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
36635 * @param {TreePanel} tree
36636 * @param {Object} config (optional)
36638 Roo.tree.TreeFilter = function(tree, config){
36640 this.filtered = {};
36641 Roo.apply(this, config);
36644 Roo.tree.TreeFilter.prototype = {
36651 * Filter the data by a specific attribute.
36652 * @param {String/RegExp} value Either string that the attribute value
36653 * should start with or a RegExp to test against the attribute
36654 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
36655 * @param {TreeNode} startNode (optional) The node to start the filter at.
36657 filter : function(value, attr, startNode){
36658 attr = attr || "text";
36660 if(typeof value == "string"){
36661 var vlen = value.length;
36662 // auto clear empty filter
36663 if(vlen == 0 && this.clearBlank){
36667 value = value.toLowerCase();
36669 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
36671 }else if(value.exec){ // regex?
36673 return value.test(n.attributes[attr]);
36676 throw 'Illegal filter type, must be string or regex';
36678 this.filterBy(f, null, startNode);
36682 * Filter by a function. The passed function will be called with each
36683 * node in the tree (or from the startNode). If the function returns true, the node is kept
36684 * otherwise it is filtered. If a node is filtered, its children are also filtered.
36685 * @param {Function} fn The filter function
36686 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
36688 filterBy : function(fn, scope, startNode){
36689 startNode = startNode || this.tree.root;
36690 if(this.autoClear){
36693 var af = this.filtered, rv = this.reverse;
36694 var f = function(n){
36695 if(n == startNode){
36701 var m = fn.call(scope || n, n);
36709 startNode.cascade(f);
36712 if(typeof id != "function"){
36714 if(n && n.parentNode){
36715 n.parentNode.removeChild(n);
36723 * Clears the current filter. Note: with the "remove" option
36724 * set a filter cannot be cleared.
36726 clear : function(){
36728 var af = this.filtered;
36730 if(typeof id != "function"){
36737 this.filtered = {};
36742 * Ext JS Library 1.1.1
36743 * Copyright(c) 2006-2007, Ext JS, LLC.
36745 * Originally Released Under LGPL - original licence link has changed is not relivant.
36748 * <script type="text/javascript">
36753 * @class Roo.tree.TreeSorter
36754 * Provides sorting of nodes in a TreePanel
36756 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
36757 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
36758 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
36759 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
36760 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
36761 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
36763 * @param {TreePanel} tree
36764 * @param {Object} config
36766 Roo.tree.TreeSorter = function(tree, config){
36767 Roo.apply(this, config);
36768 tree.on("beforechildrenrendered", this.doSort, this);
36769 tree.on("append", this.updateSort, this);
36770 tree.on("insert", this.updateSort, this);
36772 var dsc = this.dir && this.dir.toLowerCase() == "desc";
36773 var p = this.property || "text";
36774 var sortType = this.sortType;
36775 var fs = this.folderSort;
36776 var cs = this.caseSensitive === true;
36777 var leafAttr = this.leafAttr || 'leaf';
36779 this.sortFn = function(n1, n2){
36781 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
36784 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
36788 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
36789 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
36791 return dsc ? +1 : -1;
36793 return dsc ? -1 : +1;
36800 Roo.tree.TreeSorter.prototype = {
36801 doSort : function(node){
36802 node.sort(this.sortFn);
36805 compareNodes : function(n1, n2){
36806 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
36809 updateSort : function(tree, node){
36810 if(node.childrenRendered){
36811 this.doSort.defer(1, this, [node]);
36816 * Ext JS Library 1.1.1
36817 * Copyright(c) 2006-2007, Ext JS, LLC.
36819 * Originally Released Under LGPL - original licence link has changed is not relivant.
36822 * <script type="text/javascript">
36825 if(Roo.dd.DropZone){
36827 Roo.tree.TreeDropZone = function(tree, config){
36828 this.allowParentInsert = false;
36829 this.allowContainerDrop = false;
36830 this.appendOnly = false;
36831 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
36833 this.lastInsertClass = "x-tree-no-status";
36834 this.dragOverData = {};
36837 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
36838 ddGroup : "TreeDD",
36841 expandDelay : 1000,
36843 expandNode : function(node){
36844 if(node.hasChildNodes() && !node.isExpanded()){
36845 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
36849 queueExpand : function(node){
36850 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
36853 cancelExpand : function(){
36854 if(this.expandProcId){
36855 clearTimeout(this.expandProcId);
36856 this.expandProcId = false;
36860 isValidDropPoint : function(n, pt, dd, e, data){
36861 if(!n || !data){ return false; }
36862 var targetNode = n.node;
36863 var dropNode = data.node;
36864 // default drop rules
36865 if(!(targetNode && targetNode.isTarget && pt)){
36868 if(pt == "append" && targetNode.allowChildren === false){
36871 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
36874 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
36877 // reuse the object
36878 var overEvent = this.dragOverData;
36879 overEvent.tree = this.tree;
36880 overEvent.target = targetNode;
36881 overEvent.data = data;
36882 overEvent.point = pt;
36883 overEvent.source = dd;
36884 overEvent.rawEvent = e;
36885 overEvent.dropNode = dropNode;
36886 overEvent.cancel = false;
36887 var result = this.tree.fireEvent("nodedragover", overEvent);
36888 return overEvent.cancel === false && result !== false;
36891 getDropPoint : function(e, n, dd)
36895 return tn.allowChildren !== false ? "append" : false; // always append for root
36897 var dragEl = n.ddel;
36898 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
36899 var y = Roo.lib.Event.getPageY(e);
36900 //var noAppend = tn.allowChildren === false || tn.isLeaf();
36902 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
36903 var noAppend = tn.allowChildren === false;
36904 if(this.appendOnly || tn.parentNode.allowChildren === false){
36905 return noAppend ? false : "append";
36907 var noBelow = false;
36908 if(!this.allowParentInsert){
36909 noBelow = tn.hasChildNodes() && tn.isExpanded();
36911 var q = (b - t) / (noAppend ? 2 : 3);
36912 if(y >= t && y < (t + q)){
36914 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
36921 onNodeEnter : function(n, dd, e, data)
36923 this.cancelExpand();
36926 onNodeOver : function(n, dd, e, data)
36929 var pt = this.getDropPoint(e, n, dd);
36932 // auto node expand check
36933 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
36934 this.queueExpand(node);
36935 }else if(pt != "append"){
36936 this.cancelExpand();
36939 // set the insert point style on the target node
36940 var returnCls = this.dropNotAllowed;
36941 if(this.isValidDropPoint(n, pt, dd, e, data)){
36946 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
36947 cls = "x-tree-drag-insert-above";
36948 }else if(pt == "below"){
36949 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
36950 cls = "x-tree-drag-insert-below";
36952 returnCls = "x-tree-drop-ok-append";
36953 cls = "x-tree-drag-append";
36955 if(this.lastInsertClass != cls){
36956 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
36957 this.lastInsertClass = cls;
36964 onNodeOut : function(n, dd, e, data){
36966 this.cancelExpand();
36967 this.removeDropIndicators(n);
36970 onNodeDrop : function(n, dd, e, data){
36971 var point = this.getDropPoint(e, n, dd);
36972 var targetNode = n.node;
36973 targetNode.ui.startDrop();
36974 if(!this.isValidDropPoint(n, point, dd, e, data)){
36975 targetNode.ui.endDrop();
36978 // first try to find the drop node
36979 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
36982 target: targetNode,
36987 dropNode: dropNode,
36990 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
36991 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
36992 targetNode.ui.endDrop();
36995 // allow target changing
36996 targetNode = dropEvent.target;
36997 if(point == "append" && !targetNode.isExpanded()){
36998 targetNode.expand(false, null, function(){
36999 this.completeDrop(dropEvent);
37000 }.createDelegate(this));
37002 this.completeDrop(dropEvent);
37007 completeDrop : function(de){
37008 var ns = de.dropNode, p = de.point, t = de.target;
37009 if(!(ns instanceof Array)){
37013 for(var i = 0, len = ns.length; i < len; i++){
37016 t.parentNode.insertBefore(n, t);
37017 }else if(p == "below"){
37018 t.parentNode.insertBefore(n, t.nextSibling);
37024 if(this.tree.hlDrop){
37028 this.tree.fireEvent("nodedrop", de);
37031 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
37032 if(this.tree.hlDrop){
37033 dropNode.ui.focus();
37034 dropNode.ui.highlight();
37036 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
37039 getTree : function(){
37043 removeDropIndicators : function(n){
37046 Roo.fly(el).removeClass([
37047 "x-tree-drag-insert-above",
37048 "x-tree-drag-insert-below",
37049 "x-tree-drag-append"]);
37050 this.lastInsertClass = "_noclass";
37054 beforeDragDrop : function(target, e, id){
37055 this.cancelExpand();
37059 afterRepair : function(data){
37060 if(data && Roo.enableFx){
37061 data.node.ui.highlight();
37071 * Ext JS Library 1.1.1
37072 * Copyright(c) 2006-2007, Ext JS, LLC.
37074 * Originally Released Under LGPL - original licence link has changed is not relivant.
37077 * <script type="text/javascript">
37081 if(Roo.dd.DragZone){
37082 Roo.tree.TreeDragZone = function(tree, config){
37083 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
37087 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
37088 ddGroup : "TreeDD",
37090 onBeforeDrag : function(data, e){
37092 return n && n.draggable && !n.disabled;
37096 onInitDrag : function(e){
37097 var data = this.dragData;
37098 this.tree.getSelectionModel().select(data.node);
37099 this.proxy.update("");
37100 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
37101 this.tree.fireEvent("startdrag", this.tree, data.node, e);
37104 getRepairXY : function(e, data){
37105 return data.node.ui.getDDRepairXY();
37108 onEndDrag : function(data, e){
37109 this.tree.fireEvent("enddrag", this.tree, data.node, e);
37114 onValidDrop : function(dd, e, id){
37115 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
37119 beforeInvalidDrop : function(e, id){
37120 // this scrolls the original position back into view
37121 var sm = this.tree.getSelectionModel();
37122 sm.clearSelections();
37123 sm.select(this.dragData.node);
37128 * Ext JS Library 1.1.1
37129 * Copyright(c) 2006-2007, Ext JS, LLC.
37131 * Originally Released Under LGPL - original licence link has changed is not relivant.
37134 * <script type="text/javascript">
37137 * @class Roo.tree.TreeEditor
37138 * @extends Roo.Editor
37139 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
37140 * as the editor field.
37142 * @param {Object} config (used to be the tree panel.)
37143 * @param {Object} oldconfig DEPRECIATED Either a prebuilt {@link Roo.form.Field} instance or a Field config object
37145 * @cfg {Roo.tree.TreePanel} tree The tree to bind to.
37146 * @cfg {Roo.form.TextField} field [required] The field configuration
37150 Roo.tree.TreeEditor = function(config, oldconfig) { // was -- (tree, config){
37153 if (oldconfig) { // old style..
37154 field = oldconfig.events ? oldconfig : new Roo.form.TextField(oldconfig);
37157 tree = config.tree;
37158 config.field = config.field || {};
37159 config.field.xtype = 'TextField';
37160 field = Roo.factory(config.field, Roo.form);
37162 config = config || {};
37167 * @event beforenodeedit
37168 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
37169 * false from the handler of this event.
37170 * @param {Editor} this
37171 * @param {Roo.tree.Node} node
37173 "beforenodeedit" : true
37177 Roo.tree.TreeEditor.superclass.constructor.call(this, field, config);
37181 tree.on('beforeclick', this.beforeNodeClick, this);
37182 tree.getTreeEl().on('mousedown', this.hide, this);
37183 this.on('complete', this.updateNode, this);
37184 this.on('beforestartedit', this.fitToTree, this);
37185 this.on('startedit', this.bindScroll, this, {delay:10});
37186 this.on('specialkey', this.onSpecialKey, this);
37189 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
37191 * @cfg {String} alignment
37192 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
37198 * @cfg {Boolean} hideEl
37199 * True to hide the bound element while the editor is displayed (defaults to false)
37203 * @cfg {String} cls
37204 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
37206 cls: "x-small-editor x-tree-editor",
37208 * @cfg {Boolean} shim
37209 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
37215 * @cfg {Number} maxWidth
37216 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
37217 * the containing tree element's size, it will be automatically limited for you to the container width, taking
37218 * scroll and client offsets into account prior to each edit.
37225 fitToTree : function(ed, el){
37226 var td = this.tree.getTreeEl().dom, nd = el.dom;
37227 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
37228 td.scrollLeft = nd.offsetLeft;
37232 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
37233 this.setSize(w, '');
37235 return this.fireEvent('beforenodeedit', this, this.editNode);
37240 triggerEdit : function(node){
37241 this.completeEdit();
37242 this.editNode = node;
37243 this.startEdit(node.ui.textNode, node.text);
37247 bindScroll : function(){
37248 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
37252 beforeNodeClick : function(node, e){
37253 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
37254 this.lastClick = new Date();
37255 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
37257 this.triggerEdit(node);
37264 updateNode : function(ed, value){
37265 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
37266 this.editNode.setText(value);
37270 onHide : function(){
37271 Roo.tree.TreeEditor.superclass.onHide.call(this);
37273 this.editNode.ui.focus();
37278 onSpecialKey : function(field, e){
37279 var k = e.getKey();
37283 }else if(k == e.ENTER && !e.hasModifier()){
37285 this.completeEdit();
37288 });//<Script type="text/javascript">
37291 * Ext JS Library 1.1.1
37292 * Copyright(c) 2006-2007, Ext JS, LLC.
37294 * Originally Released Under LGPL - original licence link has changed is not relivant.
37297 * <script type="text/javascript">
37301 * Not documented??? - probably should be...
37304 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
37305 //focus: Roo.emptyFn, // prevent odd scrolling behavior
37307 renderElements : function(n, a, targetNode, bulkRender){
37308 //consel.log("renderElements?");
37309 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
37311 var t = n.getOwnerTree();
37312 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
37314 var cols = t.columns;
37315 var bw = t.borderWidth;
37317 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
37318 var cb = typeof a.checked == "boolean";
37319 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
37320 var colcls = 'x-t-' + tid + '-c0';
37322 '<li class="x-tree-node">',
37325 '<div class="x-tree-node-el ', a.cls,'">',
37327 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
37330 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
37331 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
37332 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
37333 (a.icon ? ' x-tree-node-inline-icon' : ''),
37334 (a.iconCls ? ' '+a.iconCls : ''),
37335 '" unselectable="on" />',
37336 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
37337 (a.checked ? 'checked="checked" />' : ' />')) : ''),
37339 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
37340 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
37341 '<span unselectable="on" qtip="' + tx + '">',
37345 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
37346 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
37348 for(var i = 1, len = cols.length; i < len; i++){
37350 colcls = 'x-t-' + tid + '-c' +i;
37351 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
37352 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
37353 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
37359 '<div class="x-clear"></div></div>',
37360 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
37363 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
37364 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
37365 n.nextSibling.ui.getEl(), buf.join(""));
37367 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
37369 var el = this.wrap.firstChild;
37371 this.elNode = el.firstChild;
37372 this.ranchor = el.childNodes[1];
37373 this.ctNode = this.wrap.childNodes[1];
37374 var cs = el.firstChild.childNodes;
37375 this.indentNode = cs[0];
37376 this.ecNode = cs[1];
37377 this.iconNode = cs[2];
37380 this.checkbox = cs[3];
37383 this.anchor = cs[index];
37385 this.textNode = cs[index].firstChild;
37387 //el.on("click", this.onClick, this);
37388 //el.on("dblclick", this.onDblClick, this);
37391 // console.log(this);
37393 initEvents : function(){
37394 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
37397 var a = this.ranchor;
37399 var el = Roo.get(a);
37401 if(Roo.isOpera){ // opera render bug ignores the CSS
37402 el.setStyle("text-decoration", "none");
37405 el.on("click", this.onClick, this);
37406 el.on("dblclick", this.onDblClick, this);
37407 el.on("contextmenu", this.onContextMenu, this);
37411 /*onSelectedChange : function(state){
37414 this.addClass("x-tree-selected");
37417 this.removeClass("x-tree-selected");
37420 addClass : function(cls){
37422 Roo.fly(this.elRow).addClass(cls);
37428 removeClass : function(cls){
37430 Roo.fly(this.elRow).removeClass(cls);
37436 });//<Script type="text/javascript">
37440 * Ext JS Library 1.1.1
37441 * Copyright(c) 2006-2007, Ext JS, LLC.
37443 * Originally Released Under LGPL - original licence link has changed is not relivant.
37446 * <script type="text/javascript">
37451 * @class Roo.tree.ColumnTree
37452 * @extends Roo.data.TreePanel
37453 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
37454 * @cfg {int} borderWidth compined right/left border allowance
37456 * @param {String/HTMLElement/Element} el The container element
37457 * @param {Object} config
37459 Roo.tree.ColumnTree = function(el, config)
37461 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
37465 * Fire this event on a container when it resizes
37466 * @param {int} w Width
37467 * @param {int} h Height
37471 this.on('resize', this.onResize, this);
37474 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
37478 borderWidth: Roo.isBorderBox ? 0 : 2,
37481 render : function(){
37482 // add the header.....
37484 Roo.tree.ColumnTree.superclass.render.apply(this);
37486 this.el.addClass('x-column-tree');
37488 this.headers = this.el.createChild(
37489 {cls:'x-tree-headers'},this.innerCt.dom);
37491 var cols = this.columns, c;
37492 var totalWidth = 0;
37494 var len = cols.length;
37495 for(var i = 0; i < len; i++){
37497 totalWidth += c.width;
37498 this.headEls.push(this.headers.createChild({
37499 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
37501 cls:'x-tree-hd-text',
37504 style:'width:'+(c.width-this.borderWidth)+'px;'
37507 this.headers.createChild({cls:'x-clear'});
37508 // prevent floats from wrapping when clipped
37509 this.headers.setWidth(totalWidth);
37510 //this.innerCt.setWidth(totalWidth);
37511 this.innerCt.setStyle({ overflow: 'auto' });
37512 this.onResize(this.width, this.height);
37516 onResize : function(w,h)
37521 this.innerCt.setWidth(this.width);
37522 this.innerCt.setHeight(this.height-20);
37525 var cols = this.columns, c;
37526 var totalWidth = 0;
37528 var len = cols.length;
37529 for(var i = 0; i < len; i++){
37531 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
37532 // it's the expander..
37533 expEl = this.headEls[i];
37536 totalWidth += c.width;
37540 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
37542 this.headers.setWidth(w-20);
37551 * Ext JS Library 1.1.1
37552 * Copyright(c) 2006-2007, Ext JS, LLC.
37554 * Originally Released Under LGPL - original licence link has changed is not relivant.
37557 * <script type="text/javascript">
37561 * @class Roo.menu.Menu
37562 * @extends Roo.util.Observable
37563 * @children Roo.menu.BaseItem
37564 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
37565 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
37567 * Creates a new Menu
37568 * @param {Object} config Configuration options
37570 Roo.menu.Menu = function(config){
37572 Roo.menu.Menu.superclass.constructor.call(this, config);
37574 this.id = this.id || Roo.id();
37577 * @event beforeshow
37578 * Fires before this menu is displayed
37579 * @param {Roo.menu.Menu} this
37583 * @event beforehide
37584 * Fires before this menu is hidden
37585 * @param {Roo.menu.Menu} this
37590 * Fires after this menu is displayed
37591 * @param {Roo.menu.Menu} this
37596 * Fires after this menu is hidden
37597 * @param {Roo.menu.Menu} this
37602 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
37603 * @param {Roo.menu.Menu} this
37604 * @param {Roo.menu.Item} menuItem The menu item that was clicked
37605 * @param {Roo.EventObject} e
37610 * Fires when the mouse is hovering over this menu
37611 * @param {Roo.menu.Menu} this
37612 * @param {Roo.EventObject} e
37613 * @param {Roo.menu.Item} menuItem The menu item that was clicked
37618 * Fires when the mouse exits this menu
37619 * @param {Roo.menu.Menu} this
37620 * @param {Roo.EventObject} e
37621 * @param {Roo.menu.Item} menuItem The menu item that was clicked
37626 * Fires when a menu item contained in this menu is clicked
37627 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
37628 * @param {Roo.EventObject} e
37632 if (this.registerMenu) {
37633 Roo.menu.MenuMgr.register(this);
37636 var mis = this.items;
37637 this.items = new Roo.util.MixedCollection();
37639 this.add.apply(this, mis);
37643 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
37645 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
37649 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
37650 * for bottom-right shadow (defaults to "sides")
37654 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
37655 * this menu (defaults to "tl-tr?")
37657 subMenuAlign : "tl-tr?",
37659 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
37660 * relative to its element of origin (defaults to "tl-bl?")
37662 defaultAlign : "tl-bl?",
37664 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
37666 allowOtherMenus : false,
37668 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
37670 registerMenu : true,
37675 render : function(){
37679 var el = this.el = new Roo.Layer({
37681 shadow:this.shadow,
37683 parentEl: this.parentEl || document.body,
37687 this.keyNav = new Roo.menu.MenuNav(this);
37690 el.addClass("x-menu-plain");
37693 el.addClass(this.cls);
37695 // generic focus element
37696 this.focusEl = el.createChild({
37697 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
37699 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
37700 //disabling touch- as it's causing issues ..
37701 //ul.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
37702 ul.on('click' , this.onClick, this);
37705 ul.on("mouseover", this.onMouseOver, this);
37706 ul.on("mouseout", this.onMouseOut, this);
37707 this.items.each(function(item){
37712 var li = document.createElement("li");
37713 li.className = "x-menu-list-item";
37714 ul.dom.appendChild(li);
37715 item.render(li, this);
37722 autoWidth : function(){
37723 var el = this.el, ul = this.ul;
37727 var w = this.width;
37730 }else if(Roo.isIE){
37731 el.setWidth(this.minWidth);
37732 var t = el.dom.offsetWidth; // force recalc
37733 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
37738 delayAutoWidth : function(){
37741 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
37743 this.awTask.delay(20);
37748 findTargetItem : function(e){
37749 var t = e.getTarget(".x-menu-list-item", this.ul, true);
37750 if(t && t.menuItemId){
37751 return this.items.get(t.menuItemId);
37756 onClick : function(e){
37757 Roo.log("menu.onClick");
37758 var t = this.findTargetItem(e);
37763 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
37764 if(t == this.activeItem && t.shouldDeactivate(e)){
37765 this.activeItem.deactivate();
37766 delete this.activeItem;
37770 this.setActiveItem(t, true);
37778 this.fireEvent("click", this, t, e);
37782 setActiveItem : function(item, autoExpand){
37783 if(item != this.activeItem){
37784 if(this.activeItem){
37785 this.activeItem.deactivate();
37787 this.activeItem = item;
37788 item.activate(autoExpand);
37789 }else if(autoExpand){
37795 tryActivate : function(start, step){
37796 var items = this.items;
37797 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
37798 var item = items.get(i);
37799 if(!item.disabled && item.canActivate){
37800 this.setActiveItem(item, false);
37808 onMouseOver : function(e){
37810 if(t = this.findTargetItem(e)){
37811 if(t.canActivate && !t.disabled){
37812 this.setActiveItem(t, true);
37815 this.fireEvent("mouseover", this, e, t);
37819 onMouseOut : function(e){
37821 if(t = this.findTargetItem(e)){
37822 if(t == this.activeItem && t.shouldDeactivate(e)){
37823 this.activeItem.deactivate();
37824 delete this.activeItem;
37827 this.fireEvent("mouseout", this, e, t);
37831 * Read-only. Returns true if the menu is currently displayed, else false.
37834 isVisible : function(){
37835 return this.el && !this.hidden;
37839 * Displays this menu relative to another element
37840 * @param {String/HTMLElement/Roo.Element} element The element to align to
37841 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
37842 * the element (defaults to this.defaultAlign)
37843 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
37845 show : function(el, pos, parentMenu){
37846 this.parentMenu = parentMenu;
37850 this.fireEvent("beforeshow", this);
37851 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
37855 * Displays this menu at a specific xy position
37856 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
37857 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
37859 showAt : function(xy, parentMenu, /* private: */_e){
37860 this.parentMenu = parentMenu;
37865 this.fireEvent("beforeshow", this);
37866 xy = this.el.adjustForConstraints(xy);
37870 this.hidden = false;
37872 this.fireEvent("show", this);
37875 focus : function(){
37877 this.doFocus.defer(50, this);
37881 doFocus : function(){
37883 this.focusEl.focus();
37888 * Hides this menu and optionally all parent menus
37889 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
37891 hide : function(deep){
37892 if(this.el && this.isVisible()){
37893 this.fireEvent("beforehide", this);
37894 if(this.activeItem){
37895 this.activeItem.deactivate();
37896 this.activeItem = null;
37899 this.hidden = true;
37900 this.fireEvent("hide", this);
37902 if(deep === true && this.parentMenu){
37903 this.parentMenu.hide(true);
37908 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
37909 * Any of the following are valid:
37911 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
37912 * <li>An HTMLElement object which will be converted to a menu item</li>
37913 * <li>A menu item config object that will be created as a new menu item</li>
37914 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
37915 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
37920 var menu = new Roo.menu.Menu();
37922 // Create a menu item to add by reference
37923 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
37925 // Add a bunch of items at once using different methods.
37926 // Only the last item added will be returned.
37927 var item = menu.add(
37928 menuItem, // add existing item by ref
37929 'Dynamic Item', // new TextItem
37930 '-', // new separator
37931 { text: 'Config Item' } // new item by config
37934 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
37935 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
37938 var a = arguments, l = a.length, item;
37939 for(var i = 0; i < l; i++){
37941 if ((typeof(el) == "object") && el.xtype && el.xns) {
37942 el = Roo.factory(el, Roo.menu);
37945 if(el.render){ // some kind of Item
37946 item = this.addItem(el);
37947 }else if(typeof el == "string"){ // string
37948 if(el == "separator" || el == "-"){
37949 item = this.addSeparator();
37951 item = this.addText(el);
37953 }else if(el.tagName || el.el){ // element
37954 item = this.addElement(el);
37955 }else if(typeof el == "object"){ // must be menu item config?
37956 item = this.addMenuItem(el);
37963 * Returns this menu's underlying {@link Roo.Element} object
37964 * @return {Roo.Element} The element
37966 getEl : function(){
37974 * Adds a separator bar to the menu
37975 * @return {Roo.menu.Item} The menu item that was added
37977 addSeparator : function(){
37978 return this.addItem(new Roo.menu.Separator());
37982 * Adds an {@link Roo.Element} object to the menu
37983 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
37984 * @return {Roo.menu.Item} The menu item that was added
37986 addElement : function(el){
37987 return this.addItem(new Roo.menu.BaseItem(el));
37991 * Adds an existing object based on {@link Roo.menu.Item} to the menu
37992 * @param {Roo.menu.Item} item The menu item to add
37993 * @return {Roo.menu.Item} The menu item that was added
37995 addItem : function(item){
37996 this.items.add(item);
37998 var li = document.createElement("li");
37999 li.className = "x-menu-list-item";
38000 this.ul.dom.appendChild(li);
38001 item.render(li, this);
38002 this.delayAutoWidth();
38008 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
38009 * @param {Object} config A MenuItem config object
38010 * @return {Roo.menu.Item} The menu item that was added
38012 addMenuItem : function(config){
38013 if(!(config instanceof Roo.menu.Item)){
38014 if(typeof config.checked == "boolean"){ // must be check menu item config?
38015 config = new Roo.menu.CheckItem(config);
38017 config = new Roo.menu.Item(config);
38020 return this.addItem(config);
38024 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
38025 * @param {String} text The text to display in the menu item
38026 * @return {Roo.menu.Item} The menu item that was added
38028 addText : function(text){
38029 return this.addItem(new Roo.menu.TextItem({ text : text }));
38033 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
38034 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
38035 * @param {Roo.menu.Item} item The menu item to add
38036 * @return {Roo.menu.Item} The menu item that was added
38038 insert : function(index, item){
38039 this.items.insert(index, item);
38041 var li = document.createElement("li");
38042 li.className = "x-menu-list-item";
38043 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
38044 item.render(li, this);
38045 this.delayAutoWidth();
38051 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
38052 * @param {Roo.menu.Item} item The menu item to remove
38054 remove : function(item){
38055 this.items.removeKey(item.id);
38060 * Removes and destroys all items in the menu
38062 removeAll : function(){
38064 while(f = this.items.first()){
38070 // MenuNav is a private utility class used internally by the Menu
38071 Roo.menu.MenuNav = function(menu){
38072 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
38073 this.scope = this.menu = menu;
38076 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
38077 doRelay : function(e, h){
38078 var k = e.getKey();
38079 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
38080 this.menu.tryActivate(0, 1);
38083 return h.call(this.scope || this, e, this.menu);
38086 up : function(e, m){
38087 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
38088 m.tryActivate(m.items.length-1, -1);
38092 down : function(e, m){
38093 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
38094 m.tryActivate(0, 1);
38098 right : function(e, m){
38100 m.activeItem.expandMenu(true);
38104 left : function(e, m){
38106 if(m.parentMenu && m.parentMenu.activeItem){
38107 m.parentMenu.activeItem.activate();
38111 enter : function(e, m){
38113 e.stopPropagation();
38114 m.activeItem.onClick(e);
38115 m.fireEvent("click", this, m.activeItem);
38121 * Ext JS Library 1.1.1
38122 * Copyright(c) 2006-2007, Ext JS, LLC.
38124 * Originally Released Under LGPL - original licence link has changed is not relivant.
38127 * <script type="text/javascript">
38131 * @class Roo.menu.MenuMgr
38132 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
38135 Roo.menu.MenuMgr = function(){
38136 var menus, active, groups = {}, attached = false, lastShow = new Date();
38138 // private - called when first menu is created
38141 active = new Roo.util.MixedCollection();
38142 Roo.get(document).addKeyListener(27, function(){
38143 if(active.length > 0){
38150 function hideAll(){
38151 if(active && active.length > 0){
38152 var c = active.clone();
38153 c.each(function(m){
38160 function onHide(m){
38162 if(active.length < 1){
38163 Roo.get(document).un("mousedown", onMouseDown);
38169 function onShow(m){
38170 var last = active.last();
38171 lastShow = new Date();
38174 Roo.get(document).on("mousedown", onMouseDown);
38178 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
38179 m.parentMenu.activeChild = m;
38180 }else if(last && last.isVisible()){
38181 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
38186 function onBeforeHide(m){
38188 m.activeChild.hide();
38190 if(m.autoHideTimer){
38191 clearTimeout(m.autoHideTimer);
38192 delete m.autoHideTimer;
38197 function onBeforeShow(m){
38198 var pm = m.parentMenu;
38199 if(!pm && !m.allowOtherMenus){
38201 }else if(pm && pm.activeChild && active != m){
38202 pm.activeChild.hide();
38207 function onMouseDown(e){
38208 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
38214 function onBeforeCheck(mi, state){
38216 var g = groups[mi.group];
38217 for(var i = 0, l = g.length; i < l; i++){
38219 g[i].setChecked(false);
38228 * Hides all menus that are currently visible
38230 hideAll : function(){
38235 register : function(menu){
38239 menus[menu.id] = menu;
38240 menu.on("beforehide", onBeforeHide);
38241 menu.on("hide", onHide);
38242 menu.on("beforeshow", onBeforeShow);
38243 menu.on("show", onShow);
38244 var g = menu.group;
38245 if(g && menu.events["checkchange"]){
38249 groups[g].push(menu);
38250 menu.on("checkchange", onCheck);
38255 * Returns a {@link Roo.menu.Menu} object
38256 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
38257 * be used to generate and return a new Menu instance.
38259 get : function(menu){
38260 if(typeof menu == "string"){ // menu id
38261 return menus[menu];
38262 }else if(menu.events){ // menu instance
38264 }else if(typeof menu.length == 'number'){ // array of menu items?
38265 return new Roo.menu.Menu({items:menu});
38266 }else{ // otherwise, must be a config
38267 return new Roo.menu.Menu(menu);
38272 unregister : function(menu){
38273 delete menus[menu.id];
38274 menu.un("beforehide", onBeforeHide);
38275 menu.un("hide", onHide);
38276 menu.un("beforeshow", onBeforeShow);
38277 menu.un("show", onShow);
38278 var g = menu.group;
38279 if(g && menu.events["checkchange"]){
38280 groups[g].remove(menu);
38281 menu.un("checkchange", onCheck);
38286 registerCheckable : function(menuItem){
38287 var g = menuItem.group;
38292 groups[g].push(menuItem);
38293 menuItem.on("beforecheckchange", onBeforeCheck);
38298 unregisterCheckable : function(menuItem){
38299 var g = menuItem.group;
38301 groups[g].remove(menuItem);
38302 menuItem.un("beforecheckchange", onBeforeCheck);
38308 * Ext JS Library 1.1.1
38309 * Copyright(c) 2006-2007, Ext JS, LLC.
38311 * Originally Released Under LGPL - original licence link has changed is not relivant.
38314 * <script type="text/javascript">
38319 * @class Roo.menu.BaseItem
38320 * @extends Roo.Component
38322 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
38323 * management and base configuration options shared by all menu components.
38325 * Creates a new BaseItem
38326 * @param {Object} config Configuration options
38328 Roo.menu.BaseItem = function(config){
38329 Roo.menu.BaseItem.superclass.constructor.call(this, config);
38334 * Fires when this item is clicked
38335 * @param {Roo.menu.BaseItem} this
38336 * @param {Roo.EventObject} e
38341 * Fires when this item is activated
38342 * @param {Roo.menu.BaseItem} this
38346 * @event deactivate
38347 * Fires when this item is deactivated
38348 * @param {Roo.menu.BaseItem} this
38354 this.on("click", this.handler, this.scope, true);
38358 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
38360 * @cfg {Function} handler
38361 * A function that will handle the click event of this menu item (defaults to undefined)
38364 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
38366 canActivate : false,
38369 * @cfg {Boolean} hidden True to prevent creation of this menu item (defaults to false)
38374 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
38376 activeClass : "x-menu-item-active",
38378 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
38380 hideOnClick : true,
38382 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
38387 ctype: "Roo.menu.BaseItem",
38390 actionMode : "container",
38393 render : function(container, parentMenu){
38394 this.parentMenu = parentMenu;
38395 Roo.menu.BaseItem.superclass.render.call(this, container);
38396 this.container.menuItemId = this.id;
38400 onRender : function(container, position){
38401 this.el = Roo.get(this.el);
38402 container.dom.appendChild(this.el.dom);
38406 onClick : function(e){
38407 if(!this.disabled && this.fireEvent("click", this, e) !== false
38408 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
38409 this.handleClick(e);
38416 activate : function(){
38420 var li = this.container;
38421 li.addClass(this.activeClass);
38422 this.region = li.getRegion().adjust(2, 2, -2, -2);
38423 this.fireEvent("activate", this);
38428 deactivate : function(){
38429 this.container.removeClass(this.activeClass);
38430 this.fireEvent("deactivate", this);
38434 shouldDeactivate : function(e){
38435 return !this.region || !this.region.contains(e.getPoint());
38439 handleClick : function(e){
38440 if(this.hideOnClick){
38441 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
38446 expandMenu : function(autoActivate){
38451 hideMenu : function(){
38456 * Ext JS Library 1.1.1
38457 * Copyright(c) 2006-2007, Ext JS, LLC.
38459 * Originally Released Under LGPL - original licence link has changed is not relivant.
38462 * <script type="text/javascript">
38466 * @class Roo.menu.Adapter
38467 * @extends Roo.menu.BaseItem
38469 * 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.
38470 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
38472 * Creates a new Adapter
38473 * @param {Object} config Configuration options
38475 Roo.menu.Adapter = function(component, config){
38476 Roo.menu.Adapter.superclass.constructor.call(this, config);
38477 this.component = component;
38479 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
38481 canActivate : true,
38484 onRender : function(container, position){
38485 this.component.render(container);
38486 this.el = this.component.getEl();
38490 activate : function(){
38494 this.component.focus();
38495 this.fireEvent("activate", this);
38500 deactivate : function(){
38501 this.fireEvent("deactivate", this);
38505 disable : function(){
38506 this.component.disable();
38507 Roo.menu.Adapter.superclass.disable.call(this);
38511 enable : function(){
38512 this.component.enable();
38513 Roo.menu.Adapter.superclass.enable.call(this);
38517 * Ext JS Library 1.1.1
38518 * Copyright(c) 2006-2007, Ext JS, LLC.
38520 * Originally Released Under LGPL - original licence link has changed is not relivant.
38523 * <script type="text/javascript">
38527 * @class Roo.menu.TextItem
38528 * @extends Roo.menu.BaseItem
38529 * Adds a static text string to a menu, usually used as either a heading or group separator.
38530 * Note: old style constructor with text is still supported.
38533 * Creates a new TextItem
38534 * @param {Object} cfg Configuration
38536 Roo.menu.TextItem = function(cfg){
38537 if (typeof(cfg) == 'string') {
38540 Roo.apply(this,cfg);
38543 Roo.menu.TextItem.superclass.constructor.call(this);
38546 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
38548 * @cfg {String} text Text to show on item.
38553 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
38555 hideOnClick : false,
38557 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
38559 itemCls : "x-menu-text",
38562 onRender : function(){
38563 var s = document.createElement("span");
38564 s.className = this.itemCls;
38565 s.innerHTML = this.text;
38567 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
38571 * Ext JS Library 1.1.1
38572 * Copyright(c) 2006-2007, Ext JS, LLC.
38574 * Originally Released Under LGPL - original licence link has changed is not relivant.
38577 * <script type="text/javascript">
38581 * @class Roo.menu.Separator
38582 * @extends Roo.menu.BaseItem
38583 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
38584 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
38586 * @param {Object} config Configuration options
38588 Roo.menu.Separator = function(config){
38589 Roo.menu.Separator.superclass.constructor.call(this, config);
38592 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
38594 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
38596 itemCls : "x-menu-sep",
38598 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
38600 hideOnClick : false,
38603 onRender : function(li){
38604 var s = document.createElement("span");
38605 s.className = this.itemCls;
38606 s.innerHTML = " ";
38608 li.addClass("x-menu-sep-li");
38609 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
38613 * Ext JS Library 1.1.1
38614 * Copyright(c) 2006-2007, Ext JS, LLC.
38616 * Originally Released Under LGPL - original licence link has changed is not relivant.
38619 * <script type="text/javascript">
38622 * @class Roo.menu.Item
38623 * @extends Roo.menu.BaseItem
38624 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
38625 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
38626 * activation and click handling.
38628 * Creates a new Item
38629 * @param {Object} config Configuration options
38631 Roo.menu.Item = function(config){
38632 Roo.menu.Item.superclass.constructor.call(this, config);
38634 this.menu = Roo.menu.MenuMgr.get(this.menu);
38637 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
38639 * @cfg {Roo.menu.Menu} menu
38643 * @cfg {String} text
38644 * The text to show on the menu item.
38648 * @cfg {String} HTML to render in menu
38649 * The text to show on the menu item (HTML version).
38653 * @cfg {String} icon
38654 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
38658 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
38660 itemCls : "x-menu-item",
38662 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
38664 canActivate : true,
38666 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
38669 // doc'd in BaseItem
38673 ctype: "Roo.menu.Item",
38676 onRender : function(container, position){
38677 var el = document.createElement("a");
38678 el.hideFocus = true;
38679 el.unselectable = "on";
38680 el.href = this.href || "#";
38681 if(this.hrefTarget){
38682 el.target = this.hrefTarget;
38684 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
38686 var html = this.html.length ? this.html : String.format('{0}',this.text);
38688 el.innerHTML = String.format(
38689 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
38690 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
38692 Roo.menu.Item.superclass.onRender.call(this, container, position);
38696 * Sets the text to display in this menu item
38697 * @param {String} text The text to display
38698 * @param {Boolean} isHTML true to indicate text is pure html.
38700 setText : function(text, isHTML){
38708 var html = this.html.length ? this.html : String.format('{0}',this.text);
38710 this.el.update(String.format(
38711 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
38712 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
38713 this.parentMenu.autoWidth();
38718 handleClick : function(e){
38719 if(!this.href){ // if no link defined, stop the event automatically
38722 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
38726 activate : function(autoExpand){
38727 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
38737 shouldDeactivate : function(e){
38738 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
38739 if(this.menu && this.menu.isVisible()){
38740 return !this.menu.getEl().getRegion().contains(e.getPoint());
38748 deactivate : function(){
38749 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
38754 expandMenu : function(autoActivate){
38755 if(!this.disabled && this.menu){
38756 clearTimeout(this.hideTimer);
38757 delete this.hideTimer;
38758 if(!this.menu.isVisible() && !this.showTimer){
38759 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
38760 }else if (this.menu.isVisible() && autoActivate){
38761 this.menu.tryActivate(0, 1);
38767 deferExpand : function(autoActivate){
38768 delete this.showTimer;
38769 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
38771 this.menu.tryActivate(0, 1);
38776 hideMenu : function(){
38777 clearTimeout(this.showTimer);
38778 delete this.showTimer;
38779 if(!this.hideTimer && this.menu && this.menu.isVisible()){
38780 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
38785 deferHide : function(){
38786 delete this.hideTimer;
38791 * Ext JS Library 1.1.1
38792 * Copyright(c) 2006-2007, Ext JS, LLC.
38794 * Originally Released Under LGPL - original licence link has changed is not relivant.
38797 * <script type="text/javascript">
38801 * @class Roo.menu.CheckItem
38802 * @extends Roo.menu.Item
38803 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
38805 * Creates a new CheckItem
38806 * @param {Object} config Configuration options
38808 Roo.menu.CheckItem = function(config){
38809 Roo.menu.CheckItem.superclass.constructor.call(this, config);
38812 * @event beforecheckchange
38813 * Fires before the checked value is set, providing an opportunity to cancel if needed
38814 * @param {Roo.menu.CheckItem} this
38815 * @param {Boolean} checked The new checked value that will be set
38817 "beforecheckchange" : true,
38819 * @event checkchange
38820 * Fires after the checked value has been set
38821 * @param {Roo.menu.CheckItem} this
38822 * @param {Boolean} checked The checked value that was set
38824 "checkchange" : true
38826 if(this.checkHandler){
38827 this.on('checkchange', this.checkHandler, this.scope);
38830 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
38832 * @cfg {String} group
38833 * All check items with the same group name will automatically be grouped into a single-select
38834 * radio button group (defaults to '')
38837 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
38839 itemCls : "x-menu-item x-menu-check-item",
38841 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
38843 groupClass : "x-menu-group-item",
38846 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
38847 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
38848 * initialized with checked = true will be rendered as checked.
38853 ctype: "Roo.menu.CheckItem",
38856 onRender : function(c){
38857 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
38859 this.el.addClass(this.groupClass);
38861 Roo.menu.MenuMgr.registerCheckable(this);
38863 this.checked = false;
38864 this.setChecked(true, true);
38869 destroy : function(){
38871 Roo.menu.MenuMgr.unregisterCheckable(this);
38873 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
38877 * Set the checked state of this item
38878 * @param {Boolean} checked The new checked value
38879 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
38881 setChecked : function(state, suppressEvent){
38882 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
38883 if(this.container){
38884 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
38886 this.checked = state;
38887 if(suppressEvent !== true){
38888 this.fireEvent("checkchange", this, state);
38894 handleClick : function(e){
38895 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
38896 this.setChecked(!this.checked);
38898 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
38902 * Ext JS Library 1.1.1
38903 * Copyright(c) 2006-2007, Ext JS, LLC.
38905 * Originally Released Under LGPL - original licence link has changed is not relivant.
38908 * <script type="text/javascript">
38912 * @class Roo.menu.DateItem
38913 * @extends Roo.menu.Adapter
38914 * A menu item that wraps the {@link Roo.DatPicker} component.
38916 * Creates a new DateItem
38917 * @param {Object} config Configuration options
38919 Roo.menu.DateItem = function(config){
38920 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
38921 /** The Roo.DatePicker object @type Roo.DatePicker */
38922 this.picker = this.component;
38923 this.addEvents({select: true});
38925 this.picker.on("render", function(picker){
38926 picker.getEl().swallowEvent("click");
38927 picker.container.addClass("x-menu-date-item");
38930 this.picker.on("select", this.onSelect, this);
38933 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
38935 onSelect : function(picker, date){
38936 this.fireEvent("select", this, date, picker);
38937 Roo.menu.DateItem.superclass.handleClick.call(this);
38941 * Ext JS Library 1.1.1
38942 * Copyright(c) 2006-2007, Ext JS, LLC.
38944 * Originally Released Under LGPL - original licence link has changed is not relivant.
38947 * <script type="text/javascript">
38951 * @class Roo.menu.ColorItem
38952 * @extends Roo.menu.Adapter
38953 * A menu item that wraps the {@link Roo.ColorPalette} component.
38955 * Creates a new ColorItem
38956 * @param {Object} config Configuration options
38958 Roo.menu.ColorItem = function(config){
38959 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
38960 /** The Roo.ColorPalette object @type Roo.ColorPalette */
38961 this.palette = this.component;
38962 this.relayEvents(this.palette, ["select"]);
38963 if(this.selectHandler){
38964 this.on('select', this.selectHandler, this.scope);
38967 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
38969 * Ext JS Library 1.1.1
38970 * Copyright(c) 2006-2007, Ext JS, LLC.
38972 * Originally Released Under LGPL - original licence link has changed is not relivant.
38975 * <script type="text/javascript">
38980 * @class Roo.menu.DateMenu
38981 * @extends Roo.menu.Menu
38982 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
38984 * Creates a new DateMenu
38985 * @param {Object} config Configuration options
38987 Roo.menu.DateMenu = function(config){
38988 Roo.menu.DateMenu.superclass.constructor.call(this, config);
38990 var di = new Roo.menu.DateItem(config);
38993 * The {@link Roo.DatePicker} instance for this DateMenu
38996 this.picker = di.picker;
38999 * @param {DatePicker} picker
39000 * @param {Date} date
39002 this.relayEvents(di, ["select"]);
39003 this.on('beforeshow', function(){
39005 this.picker.hideMonthPicker(false);
39009 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
39013 * Ext JS Library 1.1.1
39014 * Copyright(c) 2006-2007, Ext JS, LLC.
39016 * Originally Released Under LGPL - original licence link has changed is not relivant.
39019 * <script type="text/javascript">
39024 * @class Roo.menu.ColorMenu
39025 * @extends Roo.menu.Menu
39026 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
39028 * Creates a new ColorMenu
39029 * @param {Object} config Configuration options
39031 Roo.menu.ColorMenu = function(config){
39032 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
39034 var ci = new Roo.menu.ColorItem(config);
39037 * The {@link Roo.ColorPalette} instance for this ColorMenu
39038 * @type ColorPalette
39040 this.palette = ci.palette;
39043 * @param {ColorPalette} palette
39044 * @param {String} color
39046 this.relayEvents(ci, ["select"]);
39048 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
39050 * Ext JS Library 1.1.1
39051 * Copyright(c) 2006-2007, Ext JS, LLC.
39053 * Originally Released Under LGPL - original licence link has changed is not relivant.
39056 * <script type="text/javascript">
39060 * @class Roo.form.TextItem
39061 * @extends Roo.BoxComponent
39062 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
39064 * Creates a new TextItem
39065 * @param {Object} config Configuration options
39067 Roo.form.TextItem = function(config){
39068 Roo.form.TextItem.superclass.constructor.call(this, config);
39071 Roo.extend(Roo.form.TextItem, Roo.BoxComponent, {
39074 * @cfg {String} tag the tag for this item (default div)
39078 * @cfg {String} html the content for this item
39082 getAutoCreate : function()
39095 onRender : function(ct, position)
39097 Roo.form.TextItem.superclass.onRender.call(this, ct, position);
39100 var cfg = this.getAutoCreate();
39102 cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
39104 if (!cfg.name.length) {
39107 this.el = ct.createChild(cfg, position);
39112 * @param {String} html update the Contents of the element.
39114 setHTML : function(html)
39116 this.fieldEl.dom.innerHTML = html;
39121 * Ext JS Library 1.1.1
39122 * Copyright(c) 2006-2007, Ext JS, LLC.
39124 * Originally Released Under LGPL - original licence link has changed is not relivant.
39127 * <script type="text/javascript">
39131 * @class Roo.form.Field
39132 * @extends Roo.BoxComponent
39133 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
39135 * Creates a new Field
39136 * @param {Object} config Configuration options
39138 Roo.form.Field = function(config){
39139 Roo.form.Field.superclass.constructor.call(this, config);
39142 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
39144 * @cfg {String} fieldLabel Label to use when rendering a form.
39147 * @cfg {String} qtip Mouse over tip
39151 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
39153 invalidClass : "x-form-invalid",
39155 * @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")
39157 invalidText : "The value in this field is invalid",
39159 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
39161 focusClass : "x-form-focus",
39163 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
39164 automatic validation (defaults to "keyup").
39166 validationEvent : "keyup",
39168 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
39170 validateOnBlur : true,
39172 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
39174 validationDelay : 250,
39176 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
39177 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
39179 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "new-password"},
39181 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
39183 fieldClass : "x-form-field",
39185 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
39188 ----------- ----------------------------------------------------------------------
39189 qtip Display a quick tip when the user hovers over the field
39190 title Display a default browser title attribute popup
39191 under Add a block div beneath the field containing the error text
39192 side Add an error icon to the right of the field with a popup on hover
39193 [element id] Add the error text directly to the innerHTML of the specified element
39196 msgTarget : 'qtip',
39198 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
39203 * @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.
39208 * @cfg {Boolean} disabled True to disable the field (defaults to false).
39213 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
39215 inputType : undefined,
39218 * @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).
39220 tabIndex : undefined,
39223 isFormField : true,
39228 * @property {Roo.Element} fieldEl
39229 * Element Containing the rendered Field (with label etc.)
39232 * @cfg {Mixed} value A value to initialize this field with.
39237 * @cfg {String} name The field's HTML name attribute.
39240 * @cfg {String} cls A CSS class to apply to the field's underlying element.
39243 loadedValue : false,
39247 initComponent : function(){
39248 Roo.form.Field.superclass.initComponent.call(this);
39252 * Fires when this field receives input focus.
39253 * @param {Roo.form.Field} this
39258 * Fires when this field loses input focus.
39259 * @param {Roo.form.Field} this
39263 * @event specialkey
39264 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
39265 * {@link Roo.EventObject#getKey} to determine which key was pressed.
39266 * @param {Roo.form.Field} this
39267 * @param {Roo.EventObject} e The event object
39272 * Fires just before the field blurs if the field value has changed.
39273 * @param {Roo.form.Field} this
39274 * @param {Mixed} newValue The new value
39275 * @param {Mixed} oldValue The original value
39280 * Fires after the field has been marked as invalid.
39281 * @param {Roo.form.Field} this
39282 * @param {String} msg The validation message
39287 * Fires after the field has been validated with no errors.
39288 * @param {Roo.form.Field} this
39293 * Fires after the key up
39294 * @param {Roo.form.Field} this
39295 * @param {Roo.EventObject} e The event Object
39302 * Returns the name attribute of the field if available
39303 * @return {String} name The field name
39305 getName: function(){
39306 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
39310 onRender : function(ct, position){
39311 Roo.form.Field.superclass.onRender.call(this, ct, position);
39313 var cfg = this.getAutoCreate();
39315 cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
39317 if (!cfg.name.length) {
39320 if(this.inputType){
39321 cfg.type = this.inputType;
39323 this.el = ct.createChild(cfg, position);
39325 var type = this.el.dom.type;
39327 if(type == 'password'){
39330 this.el.addClass('x-form-'+type);
39333 this.el.dom.readOnly = true;
39335 if(this.tabIndex !== undefined){
39336 this.el.dom.setAttribute('tabIndex', this.tabIndex);
39339 this.el.addClass([this.fieldClass, this.cls]);
39344 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
39345 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
39346 * @return {Roo.form.Field} this
39348 applyTo : function(target){
39349 this.allowDomMove = false;
39350 this.el = Roo.get(target);
39351 this.render(this.el.dom.parentNode);
39356 initValue : function(){
39357 if(this.value !== undefined){
39358 this.setValue(this.value);
39359 }else if(this.el.dom.value.length > 0){
39360 this.setValue(this.el.dom.value);
39365 * Returns true if this field has been changed since it was originally loaded and is not disabled.
39366 * DEPRICATED - it never worked well - use hasChanged/resetHasChanged.
39368 isDirty : function() {
39369 if(this.disabled) {
39372 return String(this.getValue()) !== String(this.originalValue);
39376 * stores the current value in loadedValue
39378 resetHasChanged : function()
39380 this.loadedValue = String(this.getValue());
39383 * checks the current value against the 'loaded' value.
39384 * Note - will return false if 'resetHasChanged' has not been called first.
39386 hasChanged : function()
39388 if(this.disabled || this.readOnly) {
39391 return this.loadedValue !== false && String(this.getValue()) !== this.loadedValue;
39397 afterRender : function(){
39398 Roo.form.Field.superclass.afterRender.call(this);
39403 fireKey : function(e){
39404 //Roo.log('field ' + e.getKey());
39405 if(e.isNavKeyPress()){
39406 this.fireEvent("specialkey", this, e);
39411 * Resets the current field value to the originally loaded value and clears any validation messages
39413 reset : function(){
39414 this.setValue(this.resetValue);
39415 this.originalValue = this.getValue();
39416 this.clearInvalid();
39420 initEvents : function(){
39421 // safari killled keypress - so keydown is now used..
39422 this.el.on("keydown" , this.fireKey, this);
39423 this.el.on("focus", this.onFocus, this);
39424 this.el.on("blur", this.onBlur, this);
39425 this.el.relayEvent('keyup', this);
39427 // reference to original value for reset
39428 this.originalValue = this.getValue();
39429 this.resetValue = this.getValue();
39433 onFocus : function(){
39434 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
39435 this.el.addClass(this.focusClass);
39437 if(!this.hasFocus){
39438 this.hasFocus = true;
39439 this.startValue = this.getValue();
39440 this.fireEvent("focus", this);
39444 beforeBlur : Roo.emptyFn,
39447 onBlur : function(){
39449 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
39450 this.el.removeClass(this.focusClass);
39452 this.hasFocus = false;
39453 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
39456 var v = this.getValue();
39457 if(String(v) !== String(this.startValue)){
39458 this.fireEvent('change', this, v, this.startValue);
39460 this.fireEvent("blur", this);
39464 * Returns whether or not the field value is currently valid
39465 * @param {Boolean} preventMark True to disable marking the field invalid
39466 * @return {Boolean} True if the value is valid, else false
39468 isValid : function(preventMark){
39472 var restore = this.preventMark;
39473 this.preventMark = preventMark === true;
39474 var v = this.validateValue(this.processValue(this.getRawValue()));
39475 this.preventMark = restore;
39480 * Validates the field value
39481 * @return {Boolean} True if the value is valid, else false
39483 validate : function(){
39484 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
39485 this.clearInvalid();
39491 processValue : function(value){
39496 // Subclasses should provide the validation implementation by overriding this
39497 validateValue : function(value){
39502 * Mark this field as invalid
39503 * @param {String} msg The validation message
39505 markInvalid : function(msg){
39506 if(!this.rendered || this.preventMark){ // not rendered
39510 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
39512 obj.el.addClass(this.invalidClass);
39513 msg = msg || this.invalidText;
39514 switch(this.msgTarget){
39516 obj.el.dom.qtip = msg;
39517 obj.el.dom.qclass = 'x-form-invalid-tip';
39518 if(Roo.QuickTips){ // fix for floating editors interacting with DND
39519 Roo.QuickTips.enable();
39523 this.el.dom.title = msg;
39527 var elp = this.el.findParent('.x-form-element', 5, true);
39528 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
39529 this.errorEl.setWidth(elp.getWidth(true)-20);
39531 this.errorEl.update(msg);
39532 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
39535 if(!this.errorIcon){
39536 var elp = this.el.findParent('.x-form-element', 5, true);
39537 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
39539 this.alignErrorIcon();
39540 this.errorIcon.dom.qtip = msg;
39541 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
39542 this.errorIcon.show();
39543 this.on('resize', this.alignErrorIcon, this);
39546 var t = Roo.getDom(this.msgTarget);
39548 t.style.display = this.msgDisplay;
39551 this.fireEvent('invalid', this, msg);
39555 alignErrorIcon : function(){
39556 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
39560 * Clear any invalid styles/messages for this field
39562 clearInvalid : function(){
39563 if(!this.rendered || this.preventMark){ // not rendered
39566 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
39568 obj.el.removeClass(this.invalidClass);
39569 switch(this.msgTarget){
39571 obj.el.dom.qtip = '';
39574 this.el.dom.title = '';
39578 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
39582 if(this.errorIcon){
39583 this.errorIcon.dom.qtip = '';
39584 this.errorIcon.hide();
39585 this.un('resize', this.alignErrorIcon, this);
39589 var t = Roo.getDom(this.msgTarget);
39591 t.style.display = 'none';
39594 this.fireEvent('valid', this);
39598 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
39599 * @return {Mixed} value The field value
39601 getRawValue : function(){
39602 var v = this.el.getValue();
39608 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
39609 * @return {Mixed} value The field value
39611 getValue : function(){
39612 var v = this.el.getValue();
39618 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
39619 * @param {Mixed} value The value to set
39621 setRawValue : function(v){
39622 return this.el.dom.value = (v === null || v === undefined ? '' : v);
39626 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
39627 * @param {Mixed} value The value to set
39629 setValue : function(v){
39632 this.el.dom.value = (v === null || v === undefined ? '' : v);
39637 adjustSize : function(w, h){
39638 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
39639 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
39643 adjustWidth : function(tag, w){
39644 tag = tag.toLowerCase();
39645 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
39646 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
39647 if(tag == 'input'){
39650 if(tag == 'textarea'){
39653 }else if(Roo.isOpera){
39654 if(tag == 'input'){
39657 if(tag == 'textarea'){
39667 // anything other than normal should be considered experimental
39668 Roo.form.Field.msgFx = {
39670 show: function(msgEl, f){
39671 msgEl.setDisplayed('block');
39674 hide : function(msgEl, f){
39675 msgEl.setDisplayed(false).update('');
39680 show: function(msgEl, f){
39681 msgEl.slideIn('t', {stopFx:true});
39684 hide : function(msgEl, f){
39685 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
39690 show: function(msgEl, f){
39691 msgEl.fixDisplay();
39692 msgEl.alignTo(f.el, 'tl-tr');
39693 msgEl.slideIn('l', {stopFx:true});
39696 hide : function(msgEl, f){
39697 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
39702 * Ext JS Library 1.1.1
39703 * Copyright(c) 2006-2007, Ext JS, LLC.
39705 * Originally Released Under LGPL - original licence link has changed is not relivant.
39708 * <script type="text/javascript">
39713 * @class Roo.form.TextField
39714 * @extends Roo.form.Field
39715 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
39716 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
39718 * Creates a new TextField
39719 * @param {Object} config Configuration options
39721 Roo.form.TextField = function(config){
39722 Roo.form.TextField.superclass.constructor.call(this, config);
39726 * Fires when the autosize function is triggered. The field may or may not have actually changed size
39727 * according to the default logic, but this event provides a hook for the developer to apply additional
39728 * logic at runtime to resize the field if needed.
39729 * @param {Roo.form.Field} this This text field
39730 * @param {Number} width The new field width
39736 Roo.extend(Roo.form.TextField, Roo.form.Field, {
39738 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
39742 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
39746 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
39750 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
39754 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
39758 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
39760 disableKeyFilter : false,
39762 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
39766 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
39770 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
39772 maxLength : Number.MAX_VALUE,
39774 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
39776 minLengthText : "The minimum length for this field is {0}",
39778 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
39780 maxLengthText : "The maximum length for this field is {0}",
39782 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
39784 selectOnFocus : false,
39786 * @cfg {Boolean} allowLeadingSpace True to prevent the stripping of leading white space
39788 allowLeadingSpace : false,
39790 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
39792 blankText : "This field is required",
39794 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
39795 * If available, this function will be called only after the basic validators all return true, and will be passed the
39796 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
39800 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
39801 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
39802 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
39806 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
39810 * @cfg {String} emptyText The default text to display in an empty field - placeholder... (defaults to null).
39816 initEvents : function()
39818 if (this.emptyText) {
39819 this.el.attr('placeholder', this.emptyText);
39822 Roo.form.TextField.superclass.initEvents.call(this);
39823 if(this.validationEvent == 'keyup'){
39824 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
39825 this.el.on('keyup', this.filterValidation, this);
39827 else if(this.validationEvent !== false){
39828 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
39831 if(this.selectOnFocus){
39832 this.on("focus", this.preFocus, this);
39834 if (!this.allowLeadingSpace) {
39835 this.on('blur', this.cleanLeadingSpace, this);
39838 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
39839 this.el.on("keypress", this.filterKeys, this);
39842 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
39843 this.el.on("click", this.autoSize, this);
39845 if(this.el.is('input[type=password]') && Roo.isSafari){
39846 this.el.on('keydown', this.SafariOnKeyDown, this);
39850 processValue : function(value){
39851 if(this.stripCharsRe){
39852 var newValue = value.replace(this.stripCharsRe, '');
39853 if(newValue !== value){
39854 this.setRawValue(newValue);
39861 filterValidation : function(e){
39862 if(!e.isNavKeyPress()){
39863 this.validationTask.delay(this.validationDelay);
39868 onKeyUp : function(e){
39869 if(!e.isNavKeyPress()){
39873 // private - clean the leading white space
39874 cleanLeadingSpace : function(e)
39876 if ( this.inputType == 'file') {
39880 this.setValue((this.getValue() + '').replace(/^\s+/,''));
39883 * Resets the current field value to the originally-loaded value and clears any validation messages.
39886 reset : function(){
39887 Roo.form.TextField.superclass.reset.call(this);
39891 preFocus : function(){
39893 if(this.selectOnFocus){
39894 this.el.dom.select();
39900 filterKeys : function(e){
39901 var k = e.getKey();
39902 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
39905 var c = e.getCharCode(), cc = String.fromCharCode(c);
39906 if(Roo.isIE && (e.isSpecialKey() || !cc)){
39909 if(!this.maskRe.test(cc)){
39914 setValue : function(v){
39916 Roo.form.TextField.superclass.setValue.apply(this, arguments);
39922 * Validates a value according to the field's validation rules and marks the field as invalid
39923 * if the validation fails
39924 * @param {Mixed} value The value to validate
39925 * @return {Boolean} True if the value is valid, else false
39927 validateValue : function(value){
39928 if(value.length < 1) { // if it's blank
39929 if(this.allowBlank){
39930 this.clearInvalid();
39933 this.markInvalid(this.blankText);
39937 if(value.length < this.minLength){
39938 this.markInvalid(String.format(this.minLengthText, this.minLength));
39941 if(value.length > this.maxLength){
39942 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
39946 var vt = Roo.form.VTypes;
39947 if(!vt[this.vtype](value, this)){
39948 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
39952 if(typeof this.validator == "function"){
39953 var msg = this.validator(value);
39955 this.markInvalid(msg);
39959 if(this.regex && !this.regex.test(value)){
39960 this.markInvalid(this.regexText);
39967 * Selects text in this field
39968 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
39969 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
39971 selectText : function(start, end){
39972 var v = this.getRawValue();
39974 start = start === undefined ? 0 : start;
39975 end = end === undefined ? v.length : end;
39976 var d = this.el.dom;
39977 if(d.setSelectionRange){
39978 d.setSelectionRange(start, end);
39979 }else if(d.createTextRange){
39980 var range = d.createTextRange();
39981 range.moveStart("character", start);
39982 range.moveEnd("character", v.length-end);
39989 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
39990 * This only takes effect if grow = true, and fires the autosize event.
39992 autoSize : function(){
39993 if(!this.grow || !this.rendered){
39997 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
40000 var v = el.dom.value;
40001 var d = document.createElement('div');
40002 d.appendChild(document.createTextNode(v));
40006 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
40007 this.el.setWidth(w);
40008 this.fireEvent("autosize", this, w);
40012 SafariOnKeyDown : function(event)
40014 // this is a workaround for a password hang bug on chrome/ webkit.
40016 var isSelectAll = false;
40018 if(this.el.dom.selectionEnd > 0){
40019 isSelectAll = (this.el.dom.selectionEnd - this.el.dom.selectionStart - this.getValue().length == 0) ? true : false;
40021 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
40022 event.preventDefault();
40027 if(isSelectAll && event.getCharCode() > 31){ // backspace and delete key
40029 event.preventDefault();
40030 // this is very hacky as keydown always get's upper case.
40032 var cc = String.fromCharCode(event.getCharCode());
40035 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
40043 * Ext JS Library 1.1.1
40044 * Copyright(c) 2006-2007, Ext JS, LLC.
40046 * Originally Released Under LGPL - original licence link has changed is not relivant.
40049 * <script type="text/javascript">
40053 * @class Roo.form.Hidden
40054 * @extends Roo.form.TextField
40055 * Simple Hidden element used on forms
40057 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
40060 * Creates a new Hidden form element.
40061 * @param {Object} config Configuration options
40066 // easy hidden field...
40067 Roo.form.Hidden = function(config){
40068 Roo.form.Hidden.superclass.constructor.call(this, config);
40071 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
40073 inputType: 'hidden',
40076 labelSeparator: '',
40078 itemCls : 'x-form-item-display-none'
40086 * Ext JS Library 1.1.1
40087 * Copyright(c) 2006-2007, Ext JS, LLC.
40089 * Originally Released Under LGPL - original licence link has changed is not relivant.
40092 * <script type="text/javascript">
40096 * @class Roo.form.TriggerField
40097 * @extends Roo.form.TextField
40098 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
40099 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
40100 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
40101 * for which you can provide a custom implementation. For example:
40103 var trigger = new Roo.form.TriggerField();
40104 trigger.onTriggerClick = myTriggerFn;
40105 trigger.applyTo('my-field');
40108 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
40109 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
40110 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
40111 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
40113 * Create a new TriggerField.
40114 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
40115 * to the base TextField)
40117 Roo.form.TriggerField = function(config){
40118 this.mimicing = false;
40119 Roo.form.TriggerField.superclass.constructor.call(this, config);
40122 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
40124 * @cfg {String} triggerClass A CSS class to apply to the trigger
40127 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
40128 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
40130 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "new-password"},
40132 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
40136 /** @cfg {Boolean} grow @hide */
40137 /** @cfg {Number} growMin @hide */
40138 /** @cfg {Number} growMax @hide */
40144 autoSize: Roo.emptyFn,
40148 deferHeight : true,
40151 actionMode : 'wrap',
40153 onResize : function(w, h){
40154 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
40155 if(typeof w == 'number'){
40156 var x = w - this.trigger.getWidth();
40157 this.el.setWidth(this.adjustWidth('input', x));
40158 this.trigger.setStyle('left', x+'px');
40163 adjustSize : Roo.BoxComponent.prototype.adjustSize,
40166 getResizeEl : function(){
40171 getPositionEl : function(){
40176 alignErrorIcon : function(){
40177 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
40181 onRender : function(ct, position){
40182 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
40183 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
40184 this.trigger = this.wrap.createChild(this.triggerConfig ||
40185 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
40186 if(this.hideTrigger){
40187 this.trigger.setDisplayed(false);
40189 this.initTrigger();
40191 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
40196 initTrigger : function(){
40197 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
40198 this.trigger.addClassOnOver('x-form-trigger-over');
40199 this.trigger.addClassOnClick('x-form-trigger-click');
40203 onDestroy : function(){
40205 this.trigger.removeAllListeners();
40206 this.trigger.remove();
40209 this.wrap.remove();
40211 Roo.form.TriggerField.superclass.onDestroy.call(this);
40215 onFocus : function(){
40216 Roo.form.TriggerField.superclass.onFocus.call(this);
40217 if(!this.mimicing){
40218 this.wrap.addClass('x-trigger-wrap-focus');
40219 this.mimicing = true;
40220 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
40221 if(this.monitorTab){
40222 this.el.on("keydown", this.checkTab, this);
40228 checkTab : function(e){
40229 if(e.getKey() == e.TAB){
40230 this.triggerBlur();
40235 onBlur : function(){
40240 mimicBlur : function(e, t){
40241 if(!this.wrap.contains(t) && this.validateBlur()){
40242 this.triggerBlur();
40247 triggerBlur : function(){
40248 this.mimicing = false;
40249 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
40250 if(this.monitorTab){
40251 this.el.un("keydown", this.checkTab, this);
40253 this.wrap.removeClass('x-trigger-wrap-focus');
40254 Roo.form.TriggerField.superclass.onBlur.call(this);
40258 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
40259 validateBlur : function(e, t){
40264 onDisable : function(){
40265 Roo.form.TriggerField.superclass.onDisable.call(this);
40267 this.wrap.addClass('x-item-disabled');
40272 onEnable : function(){
40273 Roo.form.TriggerField.superclass.onEnable.call(this);
40275 this.wrap.removeClass('x-item-disabled');
40280 onShow : function(){
40281 var ae = this.getActionEl();
40284 ae.dom.style.display = '';
40285 ae.dom.style.visibility = 'visible';
40291 onHide : function(){
40292 var ae = this.getActionEl();
40293 ae.dom.style.display = 'none';
40297 * The function that should handle the trigger's click event. This method does nothing by default until overridden
40298 * by an implementing function.
40300 * @param {EventObject} e
40302 onTriggerClick : Roo.emptyFn
40305 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
40306 // to be extended by an implementing class. For an example of implementing this class, see the custom
40307 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
40308 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
40309 initComponent : function(){
40310 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
40312 this.triggerConfig = {
40313 tag:'span', cls:'x-form-twin-triggers', cn:[
40314 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
40315 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
40319 getTrigger : function(index){
40320 return this.triggers[index];
40323 initTrigger : function(){
40324 var ts = this.trigger.select('.x-form-trigger', true);
40325 this.wrap.setStyle('overflow', 'hidden');
40326 var triggerField = this;
40327 ts.each(function(t, all, index){
40328 t.hide = function(){
40329 var w = triggerField.wrap.getWidth();
40330 this.dom.style.display = 'none';
40331 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
40333 t.show = function(){
40334 var w = triggerField.wrap.getWidth();
40335 this.dom.style.display = '';
40336 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
40338 var triggerIndex = 'Trigger'+(index+1);
40340 if(this['hide'+triggerIndex]){
40341 t.dom.style.display = 'none';
40343 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
40344 t.addClassOnOver('x-form-trigger-over');
40345 t.addClassOnClick('x-form-trigger-click');
40347 this.triggers = ts.elements;
40350 onTrigger1Click : Roo.emptyFn,
40351 onTrigger2Click : Roo.emptyFn
40354 * Ext JS Library 1.1.1
40355 * Copyright(c) 2006-2007, Ext JS, LLC.
40357 * Originally Released Under LGPL - original licence link has changed is not relivant.
40360 * <script type="text/javascript">
40364 * @class Roo.form.TextArea
40365 * @extends Roo.form.TextField
40366 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
40367 * support for auto-sizing.
40369 * Creates a new TextArea
40370 * @param {Object} config Configuration options
40372 Roo.form.TextArea = function(config){
40373 Roo.form.TextArea.superclass.constructor.call(this, config);
40374 // these are provided exchanges for backwards compat
40375 // minHeight/maxHeight were replaced by growMin/growMax to be
40376 // compatible with TextField growing config values
40377 if(this.minHeight !== undefined){
40378 this.growMin = this.minHeight;
40380 if(this.maxHeight !== undefined){
40381 this.growMax = this.maxHeight;
40385 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
40387 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
40391 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
40395 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
40396 * in the field (equivalent to setting overflow: hidden, defaults to false)
40398 preventScrollbars: false,
40400 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
40401 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
40405 onRender : function(ct, position){
40407 this.defaultAutoCreate = {
40409 style:"width:300px;height:60px;",
40410 autocomplete: "new-password"
40413 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
40415 this.textSizeEl = Roo.DomHelper.append(document.body, {
40416 tag: "pre", cls: "x-form-grow-sizer"
40418 if(this.preventScrollbars){
40419 this.el.setStyle("overflow", "hidden");
40421 this.el.setHeight(this.growMin);
40425 onDestroy : function(){
40426 if(this.textSizeEl){
40427 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
40429 Roo.form.TextArea.superclass.onDestroy.call(this);
40433 onKeyUp : function(e){
40434 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
40440 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
40441 * This only takes effect if grow = true, and fires the autosize event if the height changes.
40443 autoSize : function(){
40444 if(!this.grow || !this.textSizeEl){
40448 var v = el.dom.value;
40449 var ts = this.textSizeEl;
40452 ts.appendChild(document.createTextNode(v));
40455 Roo.fly(ts).setWidth(this.el.getWidth());
40457 v = "  ";
40460 v = v.replace(/\n/g, '<p> </p>');
40462 v += " \n ";
40465 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
40466 if(h != this.lastHeight){
40467 this.lastHeight = h;
40468 this.el.setHeight(h);
40469 this.fireEvent("autosize", this, h);
40474 * Ext JS Library 1.1.1
40475 * Copyright(c) 2006-2007, Ext JS, LLC.
40477 * Originally Released Under LGPL - original licence link has changed is not relivant.
40480 * <script type="text/javascript">
40485 * @class Roo.form.NumberField
40486 * @extends Roo.form.TextField
40487 * Numeric text field that provides automatic keystroke filtering and numeric validation.
40489 * Creates a new NumberField
40490 * @param {Object} config Configuration options
40492 Roo.form.NumberField = function(config){
40493 Roo.form.NumberField.superclass.constructor.call(this, config);
40496 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
40498 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
40500 fieldClass: "x-form-field x-form-num-field",
40502 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
40504 allowDecimals : true,
40506 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
40508 decimalSeparator : ".",
40510 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
40512 decimalPrecision : 2,
40514 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
40516 allowNegative : true,
40518 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
40520 minValue : Number.NEGATIVE_INFINITY,
40522 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
40524 maxValue : Number.MAX_VALUE,
40526 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
40528 minText : "The minimum value for this field is {0}",
40530 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
40532 maxText : "The maximum value for this field is {0}",
40534 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
40535 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
40537 nanText : "{0} is not a valid number",
40540 initEvents : function(){
40541 Roo.form.NumberField.superclass.initEvents.call(this);
40542 var allowed = "0123456789";
40543 if(this.allowDecimals){
40544 allowed += this.decimalSeparator;
40546 if(this.allowNegative){
40549 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
40550 var keyPress = function(e){
40551 var k = e.getKey();
40552 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40555 var c = e.getCharCode();
40556 if(allowed.indexOf(String.fromCharCode(c)) === -1){
40560 this.el.on("keypress", keyPress, this);
40564 validateValue : function(value){
40565 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
40568 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
40571 var num = this.parseValue(value);
40573 this.markInvalid(String.format(this.nanText, value));
40576 if(num < this.minValue){
40577 this.markInvalid(String.format(this.minText, this.minValue));
40580 if(num > this.maxValue){
40581 this.markInvalid(String.format(this.maxText, this.maxValue));
40587 getValue : function(){
40588 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
40592 parseValue : function(value){
40593 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
40594 return isNaN(value) ? '' : value;
40598 fixPrecision : function(value){
40599 var nan = isNaN(value);
40600 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
40601 return nan ? '' : value;
40603 return parseFloat(value).toFixed(this.decimalPrecision);
40606 setValue : function(v){
40607 v = this.fixPrecision(v);
40608 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
40612 decimalPrecisionFcn : function(v){
40613 return Math.floor(v);
40616 beforeBlur : function(){
40617 var v = this.parseValue(this.getRawValue());
40624 * Ext JS Library 1.1.1
40625 * Copyright(c) 2006-2007, Ext JS, LLC.
40627 * Originally Released Under LGPL - original licence link has changed is not relivant.
40630 * <script type="text/javascript">
40634 * @class Roo.form.DateField
40635 * @extends Roo.form.TriggerField
40636 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
40638 * Create a new DateField
40639 * @param {Object} config
40641 Roo.form.DateField = function(config)
40643 Roo.form.DateField.superclass.constructor.call(this, config);
40649 * Fires when a date is selected
40650 * @param {Roo.form.DateField} combo This combo box
40651 * @param {Date} date The date selected
40658 if(typeof this.minValue == "string") {
40659 this.minValue = this.parseDate(this.minValue);
40661 if(typeof this.maxValue == "string") {
40662 this.maxValue = this.parseDate(this.maxValue);
40664 this.ddMatch = null;
40665 if(this.disabledDates){
40666 var dd = this.disabledDates;
40668 for(var i = 0; i < dd.length; i++){
40670 if(i != dd.length-1) {
40674 this.ddMatch = new RegExp(re + ")");
40678 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
40680 * @cfg {String} format
40681 * The default date format string which can be overriden for localization support. The format must be
40682 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
40686 * @cfg {String} altFormats
40687 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
40688 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
40690 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
40692 * @cfg {Array} disabledDays
40693 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
40695 disabledDays : null,
40697 * @cfg {String} disabledDaysText
40698 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
40700 disabledDaysText : "Disabled",
40702 * @cfg {Array} disabledDates
40703 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
40704 * expression so they are very powerful. Some examples:
40706 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
40707 * <li>["03/08", "09/16"] would disable those days for every year</li>
40708 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
40709 * <li>["03/../2006"] would disable every day in March 2006</li>
40710 * <li>["^03"] would disable every day in every March</li>
40712 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
40713 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
40715 disabledDates : null,
40717 * @cfg {String} disabledDatesText
40718 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
40720 disabledDatesText : "Disabled",
40722 * @cfg {Date/String} minValue
40723 * The minimum allowed date. Can be either a Javascript date object or a string date in a
40724 * valid format (defaults to null).
40728 * @cfg {Date/String} maxValue
40729 * The maximum allowed date. Can be either a Javascript date object or a string date in a
40730 * valid format (defaults to null).
40734 * @cfg {String} minText
40735 * The error text to display when the date in the cell is before minValue (defaults to
40736 * 'The date in this field must be after {minValue}').
40738 minText : "The date in this field must be equal to or after {0}",
40740 * @cfg {String} maxText
40741 * The error text to display when the date in the cell is after maxValue (defaults to
40742 * 'The date in this field must be before {maxValue}').
40744 maxText : "The date in this field must be equal to or before {0}",
40746 * @cfg {String} invalidText
40747 * The error text to display when the date in the field is invalid (defaults to
40748 * '{value} is not a valid date - it must be in the format {format}').
40750 invalidText : "{0} is not a valid date - it must be in the format {1}",
40752 * @cfg {String} triggerClass
40753 * An additional CSS class used to style the trigger button. The trigger will always get the
40754 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
40755 * which displays a calendar icon).
40757 triggerClass : 'x-form-date-trigger',
40761 * @cfg {Boolean} useIso
40762 * if enabled, then the date field will use a hidden field to store the
40763 * real value as iso formated date. default (false)
40767 * @cfg {String/Object} autoCreate
40768 * A DomHelper element spec, or true for a default element spec (defaults to
40769 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
40772 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
40775 hiddenField: false,
40777 onRender : function(ct, position)
40779 Roo.form.DateField.superclass.onRender.call(this, ct, position);
40781 //this.el.dom.removeAttribute('name');
40782 Roo.log("Changing name?");
40783 this.el.dom.setAttribute('name', this.name + '____hidden___' );
40784 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
40786 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
40787 // prevent input submission
40788 this.hiddenName = this.name;
40795 validateValue : function(value)
40797 value = this.formatDate(value);
40798 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
40799 Roo.log('super failed');
40802 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
40805 var svalue = value;
40806 value = this.parseDate(value);
40808 Roo.log('parse date failed' + svalue);
40809 this.markInvalid(String.format(this.invalidText, svalue, this.format));
40812 var time = value.getTime();
40813 if(this.minValue && time < this.minValue.getTime()){
40814 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
40817 if(this.maxValue && time > this.maxValue.getTime()){
40818 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
40821 if(this.disabledDays){
40822 var day = value.getDay();
40823 for(var i = 0; i < this.disabledDays.length; i++) {
40824 if(day === this.disabledDays[i]){
40825 this.markInvalid(this.disabledDaysText);
40830 var fvalue = this.formatDate(value);
40831 if(this.ddMatch && this.ddMatch.test(fvalue)){
40832 this.markInvalid(String.format(this.disabledDatesText, fvalue));
40839 // Provides logic to override the default TriggerField.validateBlur which just returns true
40840 validateBlur : function(){
40841 return !this.menu || !this.menu.isVisible();
40844 getName: function()
40846 // returns hidden if it's set..
40847 if (!this.rendered) {return ''};
40848 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
40853 * Returns the current date value of the date field.
40854 * @return {Date} The date value
40856 getValue : function(){
40858 return this.hiddenField ?
40859 this.hiddenField.value :
40860 this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
40864 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
40865 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
40866 * (the default format used is "m/d/y").
40869 //All of these calls set the same date value (May 4, 2006)
40871 //Pass a date object:
40872 var dt = new Date('5/4/06');
40873 dateField.setValue(dt);
40875 //Pass a date string (default format):
40876 dateField.setValue('5/4/06');
40878 //Pass a date string (custom format):
40879 dateField.format = 'Y-m-d';
40880 dateField.setValue('2006-5-4');
40882 * @param {String/Date} date The date or valid date string
40884 setValue : function(date){
40885 if (this.hiddenField) {
40886 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
40888 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
40889 // make sure the value field is always stored as a date..
40890 this.value = this.parseDate(date);
40896 parseDate : function(value){
40897 if(!value || value instanceof Date){
40900 var v = Date.parseDate(value, this.format);
40901 if (!v && this.useIso) {
40902 v = Date.parseDate(value, 'Y-m-d');
40904 if(!v && this.altFormats){
40905 if(!this.altFormatsArray){
40906 this.altFormatsArray = this.altFormats.split("|");
40908 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
40909 v = Date.parseDate(value, this.altFormatsArray[i]);
40916 formatDate : function(date, fmt){
40917 return (!date || !(date instanceof Date)) ?
40918 date : date.dateFormat(fmt || this.format);
40923 select: function(m, d){
40926 this.fireEvent('select', this, d);
40928 show : function(){ // retain focus styling
40932 this.focus.defer(10, this);
40933 var ml = this.menuListeners;
40934 this.menu.un("select", ml.select, this);
40935 this.menu.un("show", ml.show, this);
40936 this.menu.un("hide", ml.hide, this);
40941 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
40942 onTriggerClick : function(){
40946 if(this.menu == null){
40947 this.menu = new Roo.menu.DateMenu();
40949 Roo.apply(this.menu.picker, {
40950 showClear: this.allowBlank,
40951 minDate : this.minValue,
40952 maxDate : this.maxValue,
40953 disabledDatesRE : this.ddMatch,
40954 disabledDatesText : this.disabledDatesText,
40955 disabledDays : this.disabledDays,
40956 disabledDaysText : this.disabledDaysText,
40957 format : this.useIso ? 'Y-m-d' : this.format,
40958 minText : String.format(this.minText, this.formatDate(this.minValue)),
40959 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
40961 this.menu.on(Roo.apply({}, this.menuListeners, {
40964 this.menu.picker.setValue(this.getValue() || new Date());
40965 this.menu.show(this.el, "tl-bl?");
40968 beforeBlur : function(){
40969 var v = this.parseDate(this.getRawValue());
40979 isDirty : function() {
40980 if(this.disabled) {
40984 if(typeof(this.startValue) === 'undefined'){
40988 return String(this.getValue()) !== String(this.startValue);
40992 cleanLeadingSpace : function(e)
40999 * Ext JS Library 1.1.1
41000 * Copyright(c) 2006-2007, Ext JS, LLC.
41002 * Originally Released Under LGPL - original licence link has changed is not relivant.
41005 * <script type="text/javascript">
41009 * @class Roo.form.MonthField
41010 * @extends Roo.form.TriggerField
41011 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
41013 * Create a new MonthField
41014 * @param {Object} config
41016 Roo.form.MonthField = function(config){
41018 Roo.form.MonthField.superclass.constructor.call(this, config);
41024 * Fires when a date is selected
41025 * @param {Roo.form.MonthFieeld} combo This combo box
41026 * @param {Date} date The date selected
41033 if(typeof this.minValue == "string") {
41034 this.minValue = this.parseDate(this.minValue);
41036 if(typeof this.maxValue == "string") {
41037 this.maxValue = this.parseDate(this.maxValue);
41039 this.ddMatch = null;
41040 if(this.disabledDates){
41041 var dd = this.disabledDates;
41043 for(var i = 0; i < dd.length; i++){
41045 if(i != dd.length-1) {
41049 this.ddMatch = new RegExp(re + ")");
41053 Roo.extend(Roo.form.MonthField, Roo.form.TriggerField, {
41055 * @cfg {String} format
41056 * The default date format string which can be overriden for localization support. The format must be
41057 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
41061 * @cfg {String} altFormats
41062 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
41063 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
41065 altFormats : "M Y|m/Y|m-y|m-Y|my|mY",
41067 * @cfg {Array} disabledDays
41068 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
41070 disabledDays : [0,1,2,3,4,5,6],
41072 * @cfg {String} disabledDaysText
41073 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
41075 disabledDaysText : "Disabled",
41077 * @cfg {Array} disabledDates
41078 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
41079 * expression so they are very powerful. Some examples:
41081 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
41082 * <li>["03/08", "09/16"] would disable those days for every year</li>
41083 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
41084 * <li>["03/../2006"] would disable every day in March 2006</li>
41085 * <li>["^03"] would disable every day in every March</li>
41087 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
41088 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
41090 disabledDates : null,
41092 * @cfg {String} disabledDatesText
41093 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
41095 disabledDatesText : "Disabled",
41097 * @cfg {Date/String} minValue
41098 * The minimum allowed date. Can be either a Javascript date object or a string date in a
41099 * valid format (defaults to null).
41103 * @cfg {Date/String} maxValue
41104 * The maximum allowed date. Can be either a Javascript date object or a string date in a
41105 * valid format (defaults to null).
41109 * @cfg {String} minText
41110 * The error text to display when the date in the cell is before minValue (defaults to
41111 * 'The date in this field must be after {minValue}').
41113 minText : "The date in this field must be equal to or after {0}",
41115 * @cfg {String} maxTextf
41116 * The error text to display when the date in the cell is after maxValue (defaults to
41117 * 'The date in this field must be before {maxValue}').
41119 maxText : "The date in this field must be equal to or before {0}",
41121 * @cfg {String} invalidText
41122 * The error text to display when the date in the field is invalid (defaults to
41123 * '{value} is not a valid date - it must be in the format {format}').
41125 invalidText : "{0} is not a valid date - it must be in the format {1}",
41127 * @cfg {String} triggerClass
41128 * An additional CSS class used to style the trigger button. The trigger will always get the
41129 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
41130 * which displays a calendar icon).
41132 triggerClass : 'x-form-date-trigger',
41136 * @cfg {Boolean} useIso
41137 * if enabled, then the date field will use a hidden field to store the
41138 * real value as iso formated date. default (true)
41142 * @cfg {String/Object} autoCreate
41143 * A DomHelper element spec, or true for a default element spec (defaults to
41144 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
41147 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "new-password"},
41150 hiddenField: false,
41152 hideMonthPicker : false,
41154 onRender : function(ct, position)
41156 Roo.form.MonthField.superclass.onRender.call(this, ct, position);
41158 this.el.dom.removeAttribute('name');
41159 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
41161 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
41162 // prevent input submission
41163 this.hiddenName = this.name;
41170 validateValue : function(value)
41172 value = this.formatDate(value);
41173 if(!Roo.form.MonthField.superclass.validateValue.call(this, value)){
41176 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
41179 var svalue = value;
41180 value = this.parseDate(value);
41182 this.markInvalid(String.format(this.invalidText, svalue, this.format));
41185 var time = value.getTime();
41186 if(this.minValue && time < this.minValue.getTime()){
41187 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
41190 if(this.maxValue && time > this.maxValue.getTime()){
41191 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
41194 /*if(this.disabledDays){
41195 var day = value.getDay();
41196 for(var i = 0; i < this.disabledDays.length; i++) {
41197 if(day === this.disabledDays[i]){
41198 this.markInvalid(this.disabledDaysText);
41204 var fvalue = this.formatDate(value);
41205 /*if(this.ddMatch && this.ddMatch.test(fvalue)){
41206 this.markInvalid(String.format(this.disabledDatesText, fvalue));
41214 // Provides logic to override the default TriggerField.validateBlur which just returns true
41215 validateBlur : function(){
41216 return !this.menu || !this.menu.isVisible();
41220 * Returns the current date value of the date field.
41221 * @return {Date} The date value
41223 getValue : function(){
41227 return this.hiddenField ?
41228 this.hiddenField.value :
41229 this.parseDate(Roo.form.MonthField.superclass.getValue.call(this)) || "";
41233 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
41234 * date, using MonthField.format as the date format, according to the same rules as {@link Date#parseDate}
41235 * (the default format used is "m/d/y").
41238 //All of these calls set the same date value (May 4, 2006)
41240 //Pass a date object:
41241 var dt = new Date('5/4/06');
41242 monthField.setValue(dt);
41244 //Pass a date string (default format):
41245 monthField.setValue('5/4/06');
41247 //Pass a date string (custom format):
41248 monthField.format = 'Y-m-d';
41249 monthField.setValue('2006-5-4');
41251 * @param {String/Date} date The date or valid date string
41253 setValue : function(date){
41254 Roo.log('month setValue' + date);
41255 // can only be first of month..
41257 var val = this.parseDate(date);
41259 if (this.hiddenField) {
41260 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
41262 Roo.form.MonthField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
41263 this.value = this.parseDate(date);
41267 parseDate : function(value){
41268 if(!value || value instanceof Date){
41269 value = value ? Date.parseDate(value.format('Y-m') + '-01', 'Y-m-d') : null;
41272 var v = Date.parseDate(value, this.format);
41273 if (!v && this.useIso) {
41274 v = Date.parseDate(value, 'Y-m-d');
41278 v = Date.parseDate(v.format('Y-m') +'-01', 'Y-m-d');
41282 if(!v && this.altFormats){
41283 if(!this.altFormatsArray){
41284 this.altFormatsArray = this.altFormats.split("|");
41286 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
41287 v = Date.parseDate(value, this.altFormatsArray[i]);
41294 formatDate : function(date, fmt){
41295 return (!date || !(date instanceof Date)) ?
41296 date : date.dateFormat(fmt || this.format);
41301 select: function(m, d){
41303 this.fireEvent('select', this, d);
41305 show : function(){ // retain focus styling
41309 this.focus.defer(10, this);
41310 var ml = this.menuListeners;
41311 this.menu.un("select", ml.select, this);
41312 this.menu.un("show", ml.show, this);
41313 this.menu.un("hide", ml.hide, this);
41317 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
41318 onTriggerClick : function(){
41322 if(this.menu == null){
41323 this.menu = new Roo.menu.DateMenu();
41327 Roo.apply(this.menu.picker, {
41329 showClear: this.allowBlank,
41330 minDate : this.minValue,
41331 maxDate : this.maxValue,
41332 disabledDatesRE : this.ddMatch,
41333 disabledDatesText : this.disabledDatesText,
41335 format : this.useIso ? 'Y-m-d' : this.format,
41336 minText : String.format(this.minText, this.formatDate(this.minValue)),
41337 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
41340 this.menu.on(Roo.apply({}, this.menuListeners, {
41348 // hide month picker get's called when we called by 'before hide';
41350 var ignorehide = true;
41351 p.hideMonthPicker = function(disableAnim){
41355 if(this.monthPicker){
41356 Roo.log("hideMonthPicker called");
41357 if(disableAnim === true){
41358 this.monthPicker.hide();
41360 this.monthPicker.slideOut('t', {duration:.2});
41361 p.setValue(new Date(m.picker.mpSelYear, m.picker.mpSelMonth, 1));
41362 p.fireEvent("select", this, this.value);
41368 Roo.log('picker set value');
41369 Roo.log(this.getValue());
41370 p.setValue(this.getValue() ? this.parseDate(this.getValue()) : new Date());
41371 m.show(this.el, 'tl-bl?');
41372 ignorehide = false;
41373 // this will trigger hideMonthPicker..
41376 // hidden the day picker
41377 Roo.select('.x-date-picker table', true).first().dom.style.visibility = "hidden";
41383 p.showMonthPicker.defer(100, p);
41389 beforeBlur : function(){
41390 var v = this.parseDate(this.getRawValue());
41396 /** @cfg {Boolean} grow @hide */
41397 /** @cfg {Number} growMin @hide */
41398 /** @cfg {Number} growMax @hide */
41405 * Ext JS Library 1.1.1
41406 * Copyright(c) 2006-2007, Ext JS, LLC.
41408 * Originally Released Under LGPL - original licence link has changed is not relivant.
41411 * <script type="text/javascript">
41416 * @class Roo.form.ComboBox
41417 * @extends Roo.form.TriggerField
41418 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
41420 * Create a new ComboBox.
41421 * @param {Object} config Configuration options
41423 Roo.form.ComboBox = function(config){
41424 Roo.form.ComboBox.superclass.constructor.call(this, config);
41428 * Fires when the dropdown list is expanded
41429 * @param {Roo.form.ComboBox} combo This combo box
41434 * Fires when the dropdown list is collapsed
41435 * @param {Roo.form.ComboBox} combo This combo box
41439 * @event beforeselect
41440 * Fires before a list item is selected. Return false to cancel the selection.
41441 * @param {Roo.form.ComboBox} combo This combo box
41442 * @param {Roo.data.Record} record The data record returned from the underlying store
41443 * @param {Number} index The index of the selected item in the dropdown list
41445 'beforeselect' : true,
41448 * Fires when a list item is selected
41449 * @param {Roo.form.ComboBox} combo This combo box
41450 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
41451 * @param {Number} index The index of the selected item in the dropdown list
41455 * @event beforequery
41456 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
41457 * The event object passed has these properties:
41458 * @param {Roo.form.ComboBox} combo This combo box
41459 * @param {String} query The query
41460 * @param {Boolean} forceAll true to force "all" query
41461 * @param {Boolean} cancel true to cancel the query
41462 * @param {Object} e The query event object
41464 'beforequery': true,
41467 * Fires when the 'add' icon is pressed (add a listener to enable add button)
41468 * @param {Roo.form.ComboBox} combo This combo box
41473 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
41474 * @param {Roo.form.ComboBox} combo This combo box
41475 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
41481 if(this.transform){
41482 this.allowDomMove = false;
41483 var s = Roo.getDom(this.transform);
41484 if(!this.hiddenName){
41485 this.hiddenName = s.name;
41488 this.mode = 'local';
41489 var d = [], opts = s.options;
41490 for(var i = 0, len = opts.length;i < len; i++){
41492 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
41494 this.value = value;
41496 d.push([value, o.text]);
41498 this.store = new Roo.data.SimpleStore({
41500 fields: ['value', 'text'],
41503 this.valueField = 'value';
41504 this.displayField = 'text';
41506 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
41507 if(!this.lazyRender){
41508 this.target = true;
41509 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
41510 s.parentNode.removeChild(s); // remove it
41511 this.render(this.el.parentNode);
41513 s.parentNode.removeChild(s); // remove it
41518 this.store = Roo.factory(this.store, Roo.data);
41521 this.selectedIndex = -1;
41522 if(this.mode == 'local'){
41523 if(config.queryDelay === undefined){
41524 this.queryDelay = 10;
41526 if(config.minChars === undefined){
41532 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
41534 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
41537 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
41538 * rendering into an Roo.Editor, defaults to false)
41541 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
41542 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
41545 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
41548 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
41549 * the dropdown list (defaults to undefined, with no header element)
41553 * @cfg {String/Roo.Template} tpl The template to use to render the output
41557 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
41559 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
41561 listWidth: undefined,
41563 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
41564 * mode = 'remote' or 'text' if mode = 'local')
41566 displayField: undefined,
41568 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
41569 * mode = 'remote' or 'value' if mode = 'local').
41570 * Note: use of a valueField requires the user make a selection
41571 * in order for a value to be mapped.
41573 valueField: undefined,
41577 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
41578 * field's data value (defaults to the underlying DOM element's name)
41580 hiddenName: undefined,
41582 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
41586 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
41588 selectedClass: 'x-combo-selected',
41590 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
41591 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
41592 * which displays a downward arrow icon).
41594 triggerClass : 'x-form-arrow-trigger',
41596 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
41600 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
41601 * anchor positions (defaults to 'tl-bl')
41603 listAlign: 'tl-bl?',
41605 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
41609 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
41610 * query specified by the allQuery config option (defaults to 'query')
41612 triggerAction: 'query',
41614 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
41615 * (defaults to 4, does not apply if editable = false)
41619 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
41620 * delay (typeAheadDelay) if it matches a known value (defaults to false)
41624 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
41625 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
41629 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
41630 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
41634 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
41635 * when editable = true (defaults to false)
41637 selectOnFocus:false,
41639 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
41641 queryParam: 'query',
41643 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
41644 * when mode = 'remote' (defaults to 'Loading...')
41646 loadingText: 'Loading...',
41648 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
41652 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
41656 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
41657 * traditional select (defaults to true)
41661 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
41665 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
41669 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
41670 * listWidth has a higher value)
41674 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
41675 * allow the user to set arbitrary text into the field (defaults to false)
41677 forceSelection:false,
41679 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
41680 * if typeAhead = true (defaults to 250)
41682 typeAheadDelay : 250,
41684 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
41685 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
41687 valueNotFoundText : undefined,
41689 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
41691 blockFocus : false,
41694 * @cfg {Boolean} disableClear Disable showing of clear button.
41696 disableClear : false,
41698 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
41700 alwaysQuery : false,
41706 // element that contains real text value.. (when hidden is used..)
41709 onRender : function(ct, position)
41711 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
41713 if(this.hiddenName){
41714 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
41716 this.hiddenField.value =
41717 this.hiddenValue !== undefined ? this.hiddenValue :
41718 this.value !== undefined ? this.value : '';
41720 // prevent input submission
41721 this.el.dom.removeAttribute('name');
41727 this.el.dom.setAttribute('autocomplete', 'off');
41730 var cls = 'x-combo-list';
41732 this.list = new Roo.Layer({
41733 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
41736 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
41737 this.list.setWidth(lw);
41738 this.list.swallowEvent('mousewheel');
41739 this.assetHeight = 0;
41742 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
41743 this.assetHeight += this.header.getHeight();
41746 this.innerList = this.list.createChild({cls:cls+'-inner'});
41747 this.innerList.on('mouseover', this.onViewOver, this);
41748 this.innerList.on('mousemove', this.onViewMove, this);
41749 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
41751 if(this.allowBlank && !this.pageSize && !this.disableClear){
41752 this.footer = this.list.createChild({cls:cls+'-ft'});
41753 this.pageTb = new Roo.Toolbar(this.footer);
41757 this.footer = this.list.createChild({cls:cls+'-ft'});
41758 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
41759 {pageSize: this.pageSize});
41763 if (this.pageTb && this.allowBlank && !this.disableClear) {
41765 this.pageTb.add(new Roo.Toolbar.Fill(), {
41766 cls: 'x-btn-icon x-btn-clear',
41768 handler: function()
41771 _this.clearValue();
41772 _this.onSelect(false, -1);
41777 this.assetHeight += this.footer.getHeight();
41782 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
41785 this.view = new Roo.View(this.innerList, this.tpl, {
41788 selectedClass: this.selectedClass
41791 this.view.on('click', this.onViewClick, this);
41793 this.store.on('beforeload', this.onBeforeLoad, this);
41794 this.store.on('load', this.onLoad, this);
41795 this.store.on('loadexception', this.onLoadException, this);
41797 if(this.resizable){
41798 this.resizer = new Roo.Resizable(this.list, {
41799 pinned:true, handles:'se'
41801 this.resizer.on('resize', function(r, w, h){
41802 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
41803 this.listWidth = w;
41804 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
41805 this.restrictHeight();
41807 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
41809 if(!this.editable){
41810 this.editable = true;
41811 this.setEditable(false);
41815 if (typeof(this.events.add.listeners) != 'undefined') {
41817 this.addicon = this.wrap.createChild(
41818 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
41820 this.addicon.on('click', function(e) {
41821 this.fireEvent('add', this);
41824 if (typeof(this.events.edit.listeners) != 'undefined') {
41826 this.editicon = this.wrap.createChild(
41827 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
41828 if (this.addicon) {
41829 this.editicon.setStyle('margin-left', '40px');
41831 this.editicon.on('click', function(e) {
41833 // we fire even if inothing is selected..
41834 this.fireEvent('edit', this, this.lastData );
41844 initEvents : function(){
41845 Roo.form.ComboBox.superclass.initEvents.call(this);
41847 this.keyNav = new Roo.KeyNav(this.el, {
41848 "up" : function(e){
41849 this.inKeyMode = true;
41853 "down" : function(e){
41854 if(!this.isExpanded()){
41855 this.onTriggerClick();
41857 this.inKeyMode = true;
41862 "enter" : function(e){
41863 this.onViewClick();
41867 "esc" : function(e){
41871 "tab" : function(e){
41872 this.onViewClick(false);
41873 this.fireEvent("specialkey", this, e);
41879 doRelay : function(foo, bar, hname){
41880 if(hname == 'down' || this.scope.isExpanded()){
41881 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
41888 this.queryDelay = Math.max(this.queryDelay || 10,
41889 this.mode == 'local' ? 10 : 250);
41890 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
41891 if(this.typeAhead){
41892 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
41894 if(this.editable !== false){
41895 this.el.on("keyup", this.onKeyUp, this);
41897 if(this.forceSelection){
41898 this.on('blur', this.doForce, this);
41902 onDestroy : function(){
41904 this.view.setStore(null);
41905 this.view.el.removeAllListeners();
41906 this.view.el.remove();
41907 this.view.purgeListeners();
41910 this.list.destroy();
41913 this.store.un('beforeload', this.onBeforeLoad, this);
41914 this.store.un('load', this.onLoad, this);
41915 this.store.un('loadexception', this.onLoadException, this);
41917 Roo.form.ComboBox.superclass.onDestroy.call(this);
41921 fireKey : function(e){
41922 if(e.isNavKeyPress() && !this.list.isVisible()){
41923 this.fireEvent("specialkey", this, e);
41928 onResize: function(w, h){
41929 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
41931 if(typeof w != 'number'){
41932 // we do not handle it!?!?
41935 var tw = this.trigger.getWidth();
41936 tw += this.addicon ? this.addicon.getWidth() : 0;
41937 tw += this.editicon ? this.editicon.getWidth() : 0;
41939 this.el.setWidth( this.adjustWidth('input', x));
41941 this.trigger.setStyle('left', x+'px');
41943 if(this.list && this.listWidth === undefined){
41944 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
41945 this.list.setWidth(lw);
41946 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
41954 * Allow or prevent the user from directly editing the field text. If false is passed,
41955 * the user will only be able to select from the items defined in the dropdown list. This method
41956 * is the runtime equivalent of setting the 'editable' config option at config time.
41957 * @param {Boolean} value True to allow the user to directly edit the field text
41959 setEditable : function(value){
41960 if(value == this.editable){
41963 this.editable = value;
41965 this.el.dom.setAttribute('readOnly', true);
41966 this.el.on('mousedown', this.onTriggerClick, this);
41967 this.el.addClass('x-combo-noedit');
41969 this.el.dom.setAttribute('readOnly', false);
41970 this.el.un('mousedown', this.onTriggerClick, this);
41971 this.el.removeClass('x-combo-noedit');
41976 onBeforeLoad : function(){
41977 if(!this.hasFocus){
41980 this.innerList.update(this.loadingText ?
41981 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
41982 this.restrictHeight();
41983 this.selectedIndex = -1;
41987 onLoad : function(){
41988 if(!this.hasFocus){
41991 if(this.store.getCount() > 0){
41993 this.restrictHeight();
41994 if(this.lastQuery == this.allQuery){
41996 this.el.dom.select();
41998 if(!this.selectByValue(this.value, true)){
41999 this.select(0, true);
42003 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
42004 this.taTask.delay(this.typeAheadDelay);
42008 this.onEmptyResults();
42013 onLoadException : function()
42016 Roo.log(this.store.reader.jsonData);
42017 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
42018 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
42024 onTypeAhead : function(){
42025 if(this.store.getCount() > 0){
42026 var r = this.store.getAt(0);
42027 var newValue = r.data[this.displayField];
42028 var len = newValue.length;
42029 var selStart = this.getRawValue().length;
42030 if(selStart != len){
42031 this.setRawValue(newValue);
42032 this.selectText(selStart, newValue.length);
42038 onSelect : function(record, index){
42039 if(this.fireEvent('beforeselect', this, record, index) !== false){
42040 this.setFromData(index > -1 ? record.data : false);
42042 this.fireEvent('select', this, record, index);
42047 * Returns the currently selected field value or empty string if no value is set.
42048 * @return {String} value The selected value
42050 getValue : function(){
42051 if(this.valueField){
42052 return typeof this.value != 'undefined' ? this.value : '';
42054 return Roo.form.ComboBox.superclass.getValue.call(this);
42058 * Clears any text/value currently set in the field
42060 clearValue : function(){
42061 if(this.hiddenField){
42062 this.hiddenField.value = '';
42065 this.setRawValue('');
42066 this.lastSelectionText = '';
42071 * Sets the specified value into the field. If the value finds a match, the corresponding record text
42072 * will be displayed in the field. If the value does not match the data value of an existing item,
42073 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
42074 * Otherwise the field will be blank (although the value will still be set).
42075 * @param {String} value The value to match
42077 setValue : function(v){
42079 if(this.valueField){
42080 var r = this.findRecord(this.valueField, v);
42082 text = r.data[this.displayField];
42083 }else if(this.valueNotFoundText !== undefined){
42084 text = this.valueNotFoundText;
42087 this.lastSelectionText = text;
42088 if(this.hiddenField){
42089 this.hiddenField.value = v;
42091 Roo.form.ComboBox.superclass.setValue.call(this, text);
42095 * @property {Object} the last set data for the element
42100 * Sets the value of the field based on a object which is related to the record format for the store.
42101 * @param {Object} value the value to set as. or false on reset?
42103 setFromData : function(o){
42104 var dv = ''; // display value
42105 var vv = ''; // value value..
42107 if (this.displayField) {
42108 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
42110 // this is an error condition!!!
42111 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
42114 if(this.valueField){
42115 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
42117 if(this.hiddenField){
42118 this.hiddenField.value = vv;
42120 this.lastSelectionText = dv;
42121 Roo.form.ComboBox.superclass.setValue.call(this, dv);
42125 // no hidden field.. - we store the value in 'value', but still display
42126 // display field!!!!
42127 this.lastSelectionText = dv;
42128 Roo.form.ComboBox.superclass.setValue.call(this, dv);
42134 reset : function(){
42135 // overridden so that last data is reset..
42136 this.setValue(this.resetValue);
42137 this.originalValue = this.getValue();
42138 this.clearInvalid();
42139 this.lastData = false;
42141 this.view.clearSelections();
42145 findRecord : function(prop, value){
42147 if(this.store.getCount() > 0){
42148 this.store.each(function(r){
42149 if(r.data[prop] == value){
42159 getName: function()
42161 // returns hidden if it's set..
42162 if (!this.rendered) {return ''};
42163 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
42167 onViewMove : function(e, t){
42168 this.inKeyMode = false;
42172 onViewOver : function(e, t){
42173 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
42176 var item = this.view.findItemFromChild(t);
42178 var index = this.view.indexOf(item);
42179 this.select(index, false);
42184 onViewClick : function(doFocus)
42186 var index = this.view.getSelectedIndexes()[0];
42187 var r = this.store.getAt(index);
42189 this.onSelect(r, index);
42191 if(doFocus !== false && !this.blockFocus){
42197 restrictHeight : function(){
42198 this.innerList.dom.style.height = '';
42199 var inner = this.innerList.dom;
42200 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
42201 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
42202 this.list.beginUpdate();
42203 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
42204 this.list.alignTo(this.el, this.listAlign);
42205 this.list.endUpdate();
42209 onEmptyResults : function(){
42214 * Returns true if the dropdown list is expanded, else false.
42216 isExpanded : function(){
42217 return this.list.isVisible();
42221 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
42222 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
42223 * @param {String} value The data value of the item to select
42224 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
42225 * selected item if it is not currently in view (defaults to true)
42226 * @return {Boolean} True if the value matched an item in the list, else false
42228 selectByValue : function(v, scrollIntoView){
42229 if(v !== undefined && v !== null){
42230 var r = this.findRecord(this.valueField || this.displayField, v);
42232 this.select(this.store.indexOf(r), scrollIntoView);
42240 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
42241 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
42242 * @param {Number} index The zero-based index of the list item to select
42243 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
42244 * selected item if it is not currently in view (defaults to true)
42246 select : function(index, scrollIntoView){
42247 this.selectedIndex = index;
42248 this.view.select(index);
42249 if(scrollIntoView !== false){
42250 var el = this.view.getNode(index);
42252 this.innerList.scrollChildIntoView(el, false);
42258 selectNext : function(){
42259 var ct = this.store.getCount();
42261 if(this.selectedIndex == -1){
42263 }else if(this.selectedIndex < ct-1){
42264 this.select(this.selectedIndex+1);
42270 selectPrev : function(){
42271 var ct = this.store.getCount();
42273 if(this.selectedIndex == -1){
42275 }else if(this.selectedIndex != 0){
42276 this.select(this.selectedIndex-1);
42282 onKeyUp : function(e){
42283 if(this.editable !== false && !e.isSpecialKey()){
42284 this.lastKey = e.getKey();
42285 this.dqTask.delay(this.queryDelay);
42290 validateBlur : function(){
42291 return !this.list || !this.list.isVisible();
42295 initQuery : function(){
42296 this.doQuery(this.getRawValue());
42300 doForce : function(){
42301 if(this.el.dom.value.length > 0){
42302 this.el.dom.value =
42303 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
42309 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
42310 * query allowing the query action to be canceled if needed.
42311 * @param {String} query The SQL query to execute
42312 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
42313 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
42314 * saved in the current store (defaults to false)
42316 doQuery : function(q, forceAll){
42317 if(q === undefined || q === null){
42322 forceAll: forceAll,
42326 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
42330 forceAll = qe.forceAll;
42331 if(forceAll === true || (q.length >= this.minChars)){
42332 if(this.lastQuery != q || this.alwaysQuery){
42333 this.lastQuery = q;
42334 if(this.mode == 'local'){
42335 this.selectedIndex = -1;
42337 this.store.clearFilter();
42339 this.store.filter(this.displayField, q);
42343 this.store.baseParams[this.queryParam] = q;
42345 params: this.getParams(q)
42350 this.selectedIndex = -1;
42357 getParams : function(q){
42359 //p[this.queryParam] = q;
42362 p.limit = this.pageSize;
42368 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
42370 collapse : function(){
42371 if(!this.isExpanded()){
42375 Roo.get(document).un('mousedown', this.collapseIf, this);
42376 Roo.get(document).un('mousewheel', this.collapseIf, this);
42377 if (!this.editable) {
42378 Roo.get(document).un('keydown', this.listKeyPress, this);
42380 this.fireEvent('collapse', this);
42384 collapseIf : function(e){
42385 if(!e.within(this.wrap) && !e.within(this.list)){
42391 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
42393 expand : function(){
42394 if(this.isExpanded() || !this.hasFocus){
42397 this.list.alignTo(this.el, this.listAlign);
42399 Roo.get(document).on('mousedown', this.collapseIf, this);
42400 Roo.get(document).on('mousewheel', this.collapseIf, this);
42401 if (!this.editable) {
42402 Roo.get(document).on('keydown', this.listKeyPress, this);
42405 this.fireEvent('expand', this);
42409 // Implements the default empty TriggerField.onTriggerClick function
42410 onTriggerClick : function(){
42414 if(this.isExpanded()){
42416 if (!this.blockFocus) {
42421 this.hasFocus = true;
42422 if(this.triggerAction == 'all') {
42423 this.doQuery(this.allQuery, true);
42425 this.doQuery(this.getRawValue());
42427 if (!this.blockFocus) {
42432 listKeyPress : function(e)
42434 //Roo.log('listkeypress');
42435 // scroll to first matching element based on key pres..
42436 if (e.isSpecialKey()) {
42439 var k = String.fromCharCode(e.getKey()).toUpperCase();
42442 var csel = this.view.getSelectedNodes();
42443 var cselitem = false;
42445 var ix = this.view.indexOf(csel[0]);
42446 cselitem = this.store.getAt(ix);
42447 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
42453 this.store.each(function(v) {
42455 // start at existing selection.
42456 if (cselitem.id == v.id) {
42462 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
42463 match = this.store.indexOf(v);
42468 if (match === false) {
42469 return true; // no more action?
42472 this.view.select(match);
42473 var sn = Roo.get(this.view.getSelectedNodes()[0]);
42474 sn.scrollIntoView(sn.dom.parentNode, false);
42478 * @cfg {Boolean} grow
42482 * @cfg {Number} growMin
42486 * @cfg {Number} growMax
42494 * Copyright(c) 2010-2012, Roo J Solutions Limited
42501 * @class Roo.form.ComboBoxArray
42502 * @extends Roo.form.TextField
42503 * A facebook style adder... for lists of email / people / countries etc...
42504 * pick multiple items from a combo box, and shows each one.
42506 * Fred [x] Brian [x] [Pick another |v]
42509 * For this to work: it needs various extra information
42510 * - normal combo problay has
42512 * + displayField, valueField
42514 * For our purpose...
42517 * If we change from 'extends' to wrapping...
42524 * Create a new ComboBoxArray.
42525 * @param {Object} config Configuration options
42529 Roo.form.ComboBoxArray = function(config)
42533 * @event beforeremove
42534 * Fires before remove the value from the list
42535 * @param {Roo.form.ComboBoxArray} _self This combo box array
42536 * @param {Roo.form.ComboBoxArray.Item} item removed item
42538 'beforeremove' : true,
42541 * Fires when remove the value from the list
42542 * @param {Roo.form.ComboBoxArray} _self This combo box array
42543 * @param {Roo.form.ComboBoxArray.Item} item removed item
42550 Roo.form.ComboBoxArray.superclass.constructor.call(this, config);
42552 this.items = new Roo.util.MixedCollection(false);
42554 // construct the child combo...
42564 Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
42567 * @cfg {Roo.form.ComboBox} combo [required] The combo box that is wrapped
42572 // behavies liek a hiddne field
42573 inputType: 'hidden',
42575 * @cfg {Number} width The width of the box that displays the selected element
42582 * @cfg {String} name The name of the visable items on this form (eg. titles not ids)
42586 * @cfg {String} hiddenName The hidden name of the field, often contains an comma seperated list of names
42588 hiddenName : false,
42590 * @cfg {String} seperator The value seperator normally ','
42594 // private the array of items that are displayed..
42596 // private - the hidden field el.
42598 // private - the filed el..
42601 //validateValue : function() { return true; }, // all values are ok!
42602 //onAddClick: function() { },
42604 onRender : function(ct, position)
42607 // create the standard hidden element
42608 //Roo.form.ComboBoxArray.superclass.onRender.call(this, ct, position);
42611 // give fake names to child combo;
42612 this.combo.hiddenName = this.hiddenName ? (this.hiddenName+'-subcombo') : this.hiddenName;
42613 this.combo.name = this.name ? (this.name+'-subcombo') : this.name;
42615 this.combo = Roo.factory(this.combo, Roo.form);
42616 this.combo.onRender(ct, position);
42617 if (typeof(this.combo.width) != 'undefined') {
42618 this.combo.onResize(this.combo.width,0);
42621 this.combo.initEvents();
42623 // assigned so form know we need to do this..
42624 this.store = this.combo.store;
42625 this.valueField = this.combo.valueField;
42626 this.displayField = this.combo.displayField ;
42629 this.combo.wrap.addClass('x-cbarray-grp');
42631 var cbwrap = this.combo.wrap.createChild(
42632 {tag: 'div', cls: 'x-cbarray-cb'},
42637 this.hiddenEl = this.combo.wrap.createChild({
42638 tag: 'input', type:'hidden' , name: this.hiddenName, value : ''
42640 this.el = this.combo.wrap.createChild({
42641 tag: 'input', type:'hidden' , name: this.name, value : ''
42643 // this.el.dom.removeAttribute("name");
42646 this.outerWrap = this.combo.wrap;
42647 this.wrap = cbwrap;
42649 this.outerWrap.setWidth(this.width);
42650 this.outerWrap.dom.removeChild(this.el.dom);
42652 this.wrap.dom.appendChild(this.el.dom);
42653 this.outerWrap.dom.removeChild(this.combo.trigger.dom);
42654 this.combo.wrap.dom.appendChild(this.combo.trigger.dom);
42656 this.combo.trigger.setStyle('position','relative');
42657 this.combo.trigger.setStyle('left', '0px');
42658 this.combo.trigger.setStyle('top', '2px');
42660 this.combo.el.setStyle('vertical-align', 'text-bottom');
42662 //this.trigger.setStyle('vertical-align', 'top');
42664 // this should use the code from combo really... on('add' ....)
42668 this.adder = this.outerWrap.createChild(
42669 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-adder', style: 'margin-left:2px'});
42671 this.adder.on('click', function(e) {
42672 _t.fireEvent('adderclick', this, e);
42676 //this.adder.on('click', this.onAddClick, _t);
42679 this.combo.on('select', function(cb, rec, ix) {
42680 this.addItem(rec.data);
42683 cb.el.dom.value = '';
42684 //cb.lastData = rec.data;
42693 getName: function()
42695 // returns hidden if it's set..
42696 if (!this.rendered) {return ''};
42697 return this.hiddenName ? this.hiddenName : this.name;
42702 onResize: function(w, h){
42705 // not sure if this is needed..
42706 //this.combo.onResize(w,h);
42708 if(typeof w != 'number'){
42709 // we do not handle it!?!?
42712 var tw = this.combo.trigger.getWidth();
42713 tw += this.addicon ? this.addicon.getWidth() : 0;
42714 tw += this.editicon ? this.editicon.getWidth() : 0;
42716 this.combo.el.setWidth( this.combo.adjustWidth('input', x));
42718 this.combo.trigger.setStyle('left', '0px');
42720 if(this.list && this.listWidth === undefined){
42721 var lw = Math.max(x + this.combo.trigger.getWidth(), this.combo.minListWidth);
42722 this.list.setWidth(lw);
42723 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
42730 addItem: function(rec)
42732 var valueField = this.combo.valueField;
42733 var displayField = this.combo.displayField;
42735 if (this.items.indexOfKey(rec[valueField]) > -1) {
42736 //console.log("GOT " + rec.data.id);
42740 var x = new Roo.form.ComboBoxArray.Item({
42741 //id : rec[this.idField],
42743 displayField : displayField ,
42744 tipField : displayField ,
42748 this.items.add(rec[valueField],x);
42749 // add it before the element..
42750 this.updateHiddenEl();
42751 x.render(this.outerWrap, this.wrap.dom);
42752 // add the image handler..
42755 updateHiddenEl : function()
42758 if (!this.hiddenEl) {
42762 var idField = this.combo.valueField;
42764 this.items.each(function(f) {
42765 ar.push(f.data[idField]);
42767 this.hiddenEl.dom.value = ar.join(this.seperator);
42773 this.items.clear();
42775 Roo.each(this.outerWrap.select('.x-cbarray-item', true).elements, function(el){
42779 this.el.dom.value = '';
42780 if (this.hiddenEl) {
42781 this.hiddenEl.dom.value = '';
42785 getValue: function()
42787 return this.hiddenEl ? this.hiddenEl.dom.value : '';
42789 setValue: function(v) // not a valid action - must use addItems..
42794 if (this.store.isLocal && (typeof(v) == 'string')) {
42795 // then we can use the store to find the values..
42796 // comma seperated at present.. this needs to allow JSON based encoding..
42797 this.hiddenEl.value = v;
42799 Roo.each(v.split(this.seperator), function(k) {
42800 Roo.log("CHECK " + this.valueField + ',' + k);
42801 var li = this.store.query(this.valueField, k);
42806 add[this.valueField] = k;
42807 add[this.displayField] = li.item(0).data[this.displayField];
42813 if (typeof(v) == 'object' ) {
42814 // then let's assume it's an array of objects..
42815 Roo.each(v, function(l) {
42817 if (typeof(l) == 'string') {
42819 add[this.valueField] = l;
42820 add[this.displayField] = l
42829 setFromData: function(v)
42831 // this recieves an object, if setValues is called.
42833 this.el.dom.value = v[this.displayField];
42834 this.hiddenEl.dom.value = v[this.valueField];
42835 if (typeof(v[this.valueField]) != 'string' || !v[this.valueField].length) {
42838 var kv = v[this.valueField];
42839 var dv = v[this.displayField];
42840 kv = typeof(kv) != 'string' ? '' : kv;
42841 dv = typeof(dv) != 'string' ? '' : dv;
42844 var keys = kv.split(this.seperator);
42845 var display = dv.split(this.seperator);
42846 for (var i = 0 ; i < keys.length; i++) {
42848 add[this.valueField] = keys[i];
42849 add[this.displayField] = display[i];
42857 * Validates the combox array value
42858 * @return {Boolean} True if the value is valid, else false
42860 validate : function(){
42861 if(this.disabled || this.validateValue(this.processValue(this.getValue()))){
42862 this.clearInvalid();
42868 validateValue : function(value){
42869 return Roo.form.ComboBoxArray.superclass.validateValue.call(this, this.getValue());
42877 isDirty : function() {
42878 if(this.disabled) {
42883 var d = Roo.decode(String(this.originalValue));
42885 return String(this.getValue()) !== String(this.originalValue);
42888 var originalValue = [];
42890 for (var i = 0; i < d.length; i++){
42891 originalValue.push(d[i][this.valueField]);
42894 return String(this.getValue()) !== String(originalValue.join(this.seperator));
42903 * @class Roo.form.ComboBoxArray.Item
42904 * @extends Roo.BoxComponent
42905 * A selected item in the list
42906 * Fred [x] Brian [x] [Pick another |v]
42909 * Create a new item.
42910 * @param {Object} config Configuration options
42913 Roo.form.ComboBoxArray.Item = function(config) {
42914 config.id = Roo.id();
42915 Roo.form.ComboBoxArray.Item.superclass.constructor.call(this, config);
42918 Roo.extend(Roo.form.ComboBoxArray.Item, Roo.BoxComponent, {
42921 displayField : false,
42925 defaultAutoCreate : {
42927 cls: 'x-cbarray-item',
42934 src : Roo.BLANK_IMAGE_URL ,
42942 onRender : function(ct, position)
42944 Roo.form.Field.superclass.onRender.call(this, ct, position);
42947 var cfg = this.getAutoCreate();
42948 this.el = ct.createChild(cfg, position);
42951 this.el.child('img').dom.setAttribute('src', Roo.BLANK_IMAGE_URL);
42953 this.el.child('div').dom.innerHTML = this.cb.renderer ?
42954 this.cb.renderer(this.data) :
42955 String.format('{0}',this.data[this.displayField]);
42958 this.el.child('div').dom.setAttribute('qtip',
42959 String.format('{0}',this.data[this.tipField])
42962 this.el.child('img').on('click', this.remove, this);
42966 remove : function()
42968 if(this.cb.disabled){
42972 if(false !== this.cb.fireEvent('beforeremove', this.cb, this)){
42973 this.cb.items.remove(this);
42974 this.el.child('img').un('click', this.remove, this);
42976 this.cb.updateHiddenEl();
42978 this.cb.fireEvent('remove', this.cb, this);
42983 * RooJS Library 1.1.1
42984 * Copyright(c) 2008-2011 Alan Knowles
42991 * @class Roo.form.ComboNested
42992 * @extends Roo.form.ComboBox
42993 * A combobox for that allows selection of nested items in a list,
43008 * Create a new ComboNested
43009 * @param {Object} config Configuration options
43011 Roo.form.ComboNested = function(config){
43012 Roo.form.ComboCheck.superclass.constructor.call(this, config);
43013 // should verify some data...
43015 // hiddenName = required..
43016 // displayField = required
43017 // valudField == required
43018 var req= [ 'hiddenName', 'displayField', 'valueField' ];
43020 Roo.each(req, function(e) {
43021 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
43022 throw "Roo.form.ComboNested : missing value for: " + e;
43029 Roo.extend(Roo.form.ComboNested, Roo.form.ComboBox, {
43032 * @config {Number} max Number of columns to show
43037 list : null, // the outermost div..
43038 innerLists : null, // the
43042 loadingChildren : false,
43044 onRender : function(ct, position)
43046 Roo.form.ComboBox.superclass.onRender.call(this, ct, position); // skip parent call - got to above..
43048 if(this.hiddenName){
43049 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
43051 this.hiddenField.value =
43052 this.hiddenValue !== undefined ? this.hiddenValue :
43053 this.value !== undefined ? this.value : '';
43055 // prevent input submission
43056 this.el.dom.removeAttribute('name');
43062 this.el.dom.setAttribute('autocomplete', 'off');
43065 var cls = 'x-combo-list';
43067 this.list = new Roo.Layer({
43068 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
43071 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
43072 this.list.setWidth(lw);
43073 this.list.swallowEvent('mousewheel');
43074 this.assetHeight = 0;
43077 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
43078 this.assetHeight += this.header.getHeight();
43080 this.innerLists = [];
43083 for (var i =0 ; i < this.maxColumns; i++) {
43084 this.onRenderList( cls, i);
43087 // always needs footer, as we are going to have an 'OK' button.
43088 this.footer = this.list.createChild({cls:cls+'-ft'});
43089 this.pageTb = new Roo.Toolbar(this.footer);
43094 handler: function()
43100 if ( this.allowBlank && !this.disableClear) {
43102 this.pageTb.add(new Roo.Toolbar.Fill(), {
43103 cls: 'x-btn-icon x-btn-clear',
43105 handler: function()
43108 _this.clearValue();
43109 _this.onSelect(false, -1);
43114 this.assetHeight += this.footer.getHeight();
43118 onRenderList : function ( cls, i)
43121 var lw = Math.floor(
43122 ((this.listWidth * this.maxColumns || Math.max(this.wrap.getWidth(), this.minListWidth)) - this.list.getFrameWidth('lr')) / this.maxColumns
43125 this.list.setWidth(lw); // default to '1'
43127 var il = this.innerLists[i] = this.list.createChild({cls:cls+'-inner'});
43128 //il.on('mouseover', this.onViewOver, this, { list: i });
43129 //il.on('mousemove', this.onViewMove, this, { list: i });
43131 il.setStyle({ 'overflow-x' : 'hidden'});
43134 this.tpl = new Roo.Template({
43135 html : '<div class="'+cls+'-item '+cls+'-item-{cn:this.isEmpty}">{' + this.displayField + '}</div>',
43136 isEmpty: function (value, allValues) {
43138 var dl = typeof(value.data) != 'undefined' ? value.data.length : value.length; ///json is a nested response..
43139 return dl ? 'has-children' : 'no-children'
43144 var store = this.store;
43146 store = new Roo.data.SimpleStore({
43147 //fields : this.store.reader.meta.fields,
43148 reader : this.store.reader,
43152 this.stores[i] = store;
43154 var view = this.views[i] = new Roo.View(
43160 selectedClass: this.selectedClass
43163 view.getEl().setWidth(lw);
43164 view.getEl().setStyle({
43165 position: i < 1 ? 'relative' : 'absolute',
43167 left: (i * lw ) + 'px',
43168 display : i > 0 ? 'none' : 'block'
43170 view.on('selectionchange', this.onSelectChange.createDelegate(this, {list : i }, true));
43171 view.on('dblclick', this.onDoubleClick.createDelegate(this, {list : i }, true));
43172 //view.on('click', this.onViewClick, this, { list : i });
43174 store.on('beforeload', this.onBeforeLoad, this);
43175 store.on('load', this.onLoad, this, { list : i});
43176 store.on('loadexception', this.onLoadException, this);
43178 // hide the other vies..
43184 restrictHeight : function()
43187 Roo.each(this.innerLists, function(il,i) {
43188 var el = this.views[i].getEl();
43189 el.dom.style.height = '';
43190 var inner = el.dom;
43191 var h = Math.max(il.clientHeight, il.offsetHeight, il.scrollHeight);
43192 // only adjust heights on other ones..
43193 mh = Math.max(h, mh);
43196 el.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
43197 il.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
43204 this.list.beginUpdate();
43205 this.list.setHeight(mh+this.list.getFrameWidth('tb')+this.assetHeight);
43206 this.list.alignTo(this.el, this.listAlign);
43207 this.list.endUpdate();
43212 // -- store handlers..
43214 onBeforeLoad : function()
43216 if(!this.hasFocus){
43219 this.innerLists[0].update(this.loadingText ?
43220 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
43221 this.restrictHeight();
43222 this.selectedIndex = -1;
43225 onLoad : function(a,b,c,d)
43227 if (!this.loadingChildren) {
43228 // then we are loading the top level. - hide the children
43229 for (var i = 1;i < this.views.length; i++) {
43230 this.views[i].getEl().setStyle({ display : 'none' });
43232 var lw = Math.floor(
43233 ((this.listWidth * this.maxColumns || Math.max(this.wrap.getWidth(), this.minListWidth)) - this.list.getFrameWidth('lr')) / this.maxColumns
43236 this.list.setWidth(lw); // default to '1'
43240 if(!this.hasFocus){
43244 if(this.store.getCount() > 0) {
43246 this.restrictHeight();
43248 this.onEmptyResults();
43251 if (!this.loadingChildren) {
43252 this.selectActive();
43255 this.stores[1].loadData([]);
43256 this.stores[2].loadData([]);
43265 onLoadException : function()
43268 Roo.log(this.store.reader.jsonData);
43269 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
43270 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
43275 // no cleaning of leading spaces on blur here.
43276 cleanLeadingSpace : function(e) { },
43279 onSelectChange : function (view, sels, opts )
43281 var ix = view.getSelectedIndexes();
43283 if (opts.list > this.maxColumns - 2) {
43284 if (view.store.getCount()< 1) {
43285 this.views[opts.list ].getEl().setStyle({ display : 'none' });
43289 // used to clear ?? but if we are loading unselected
43290 this.setFromData(view.store.getAt(ix[0]).data);
43299 // this get's fired when trigger opens..
43300 // this.setFromData({});
43301 var str = this.stores[opts.list+1];
43302 str.data.clear(); // removeall wihtout the fire events..
43306 var rec = view.store.getAt(ix[0]);
43308 this.setFromData(rec.data);
43309 this.fireEvent('select', this, rec, ix[0]);
43311 var lw = Math.floor(
43313 (this.listWidth * this.maxColumns || Math.max(this.wrap.getWidth(), this.minListWidth)) - this.list.getFrameWidth('lr')
43314 ) / this.maxColumns
43316 this.loadingChildren = true;
43317 this.stores[opts.list+1].loadDataFromChildren( rec );
43318 this.loadingChildren = false;
43319 var dl = this.stores[opts.list+1]. getTotalCount();
43321 this.views[opts.list+1].getEl().setHeight( this.innerLists[0].getHeight());
43323 this.views[opts.list+1].getEl().setStyle({ display : dl ? 'block' : 'none' });
43324 for (var i = opts.list+2; i < this.views.length;i++) {
43325 this.views[i].getEl().setStyle({ display : 'none' });
43328 this.innerLists[opts.list+1].setHeight( this.innerLists[0].getHeight());
43329 this.list.setWidth(lw * (opts.list + (dl ? 2 : 1)));
43331 if (this.isLoading) {
43332 // this.selectActive(opts.list);
43340 onDoubleClick : function()
43342 this.collapse(); //??
43350 recordToStack : function(store, prop, value, stack)
43352 var cstore = new Roo.data.SimpleStore({
43353 //fields : this.store.reader.meta.fields, // we need array reader.. for
43354 reader : this.store.reader,
43358 var record = false;
43360 if(store.getCount() < 1){
43363 store.each(function(r){
43364 if(r.data[prop] == value){
43369 if (r.data.cn && r.data.cn.length) {
43370 cstore.loadDataFromChildren( r);
43371 var cret = _this.recordToStack(cstore, prop, value, stack);
43372 if (cret !== false) {
43381 if (record == false) {
43384 stack.unshift(srec);
43389 * find the stack of stores that match our value.
43394 selectActive : function ()
43396 // if store is not loaded, then we will need to wait for that to happen first.
43398 this.recordToStack(this.store, this.valueField, this.getValue(), stack);
43399 for (var i = 0; i < stack.length; i++ ) {
43400 this.views[i].select(stack[i].store.indexOf(stack[i]), false, false );
43412 * Ext JS Library 1.1.1
43413 * Copyright(c) 2006-2007, Ext JS, LLC.
43415 * Originally Released Under LGPL - original licence link has changed is not relivant.
43418 * <script type="text/javascript">
43421 * @class Roo.form.Checkbox
43422 * @extends Roo.form.Field
43423 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
43425 * Creates a new Checkbox
43426 * @param {Object} config Configuration options
43428 Roo.form.Checkbox = function(config){
43429 Roo.form.Checkbox.superclass.constructor.call(this, config);
43433 * Fires when the checkbox is checked or unchecked.
43434 * @param {Roo.form.Checkbox} this This checkbox
43435 * @param {Boolean} checked The new checked value
43441 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
43443 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
43445 focusClass : undefined,
43447 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
43449 fieldClass: "x-form-field",
43451 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
43455 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
43456 * {tag: "input", type: "checkbox", autocomplete: "off"})
43458 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
43460 * @cfg {String} boxLabel The text that appears beside the checkbox
43464 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
43468 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
43470 valueOff: '0', // value when not checked..
43472 actionMode : 'viewEl',
43475 itemCls : 'x-menu-check-item x-form-item',
43476 groupClass : 'x-menu-group-item',
43477 inputType : 'hidden',
43480 inSetChecked: false, // check that we are not calling self...
43482 inputElement: false, // real input element?
43483 basedOn: false, // ????
43485 isFormField: true, // not sure where this is needed!!!!
43487 onResize : function(){
43488 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
43489 if(!this.boxLabel){
43490 this.el.alignTo(this.wrap, 'c-c');
43494 initEvents : function(){
43495 Roo.form.Checkbox.superclass.initEvents.call(this);
43496 this.el.on("click", this.onClick, this);
43497 this.el.on("change", this.onClick, this);
43501 getResizeEl : function(){
43505 getPositionEl : function(){
43510 onRender : function(ct, position){
43511 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
43513 if(this.inputValue !== undefined){
43514 this.el.dom.value = this.inputValue;
43517 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
43518 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
43519 var viewEl = this.wrap.createChild({
43520 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
43521 this.viewEl = viewEl;
43522 this.wrap.on('click', this.onClick, this);
43524 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
43525 this.el.on('propertychange', this.setFromHidden, this); //ie
43530 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
43531 // viewEl.on('click', this.onClick, this);
43533 //if(this.checked){
43534 this.setChecked(this.checked);
43536 //this.checked = this.el.dom;
43542 initValue : Roo.emptyFn,
43545 * Returns the checked state of the checkbox.
43546 * @return {Boolean} True if checked, else false
43548 getValue : function(){
43550 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
43552 return this.valueOff;
43557 onClick : function(){
43558 if (this.disabled) {
43561 this.setChecked(!this.checked);
43563 //if(this.el.dom.checked != this.checked){
43564 // this.setValue(this.el.dom.checked);
43569 * Sets the checked state of the checkbox.
43570 * On is always based on a string comparison between inputValue and the param.
43571 * @param {Boolean/String} value - the value to set
43572 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
43574 setValue : function(v,suppressEvent){
43577 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
43578 //if(this.el && this.el.dom){
43579 // this.el.dom.checked = this.checked;
43580 // this.el.dom.defaultChecked = this.checked;
43582 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
43583 //this.fireEvent("check", this, this.checked);
43586 setChecked : function(state,suppressEvent)
43588 if (this.inSetChecked) {
43589 this.checked = state;
43595 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
43597 this.checked = state;
43598 if(suppressEvent !== true){
43599 this.fireEvent('check', this, state);
43601 this.inSetChecked = true;
43602 this.el.dom.value = state ? this.inputValue : this.valueOff;
43603 this.inSetChecked = false;
43606 // handle setting of hidden value by some other method!!?!?
43607 setFromHidden: function()
43612 //console.log("SET FROM HIDDEN");
43613 //alert('setFrom hidden');
43614 this.setValue(this.el.dom.value);
43617 onDestroy : function()
43620 Roo.get(this.viewEl).remove();
43623 Roo.form.Checkbox.superclass.onDestroy.call(this);
43626 setBoxLabel : function(str)
43628 this.wrap.select('.x-form-cb-label', true).first().dom.innerHTML = str;
43633 * Ext JS Library 1.1.1
43634 * Copyright(c) 2006-2007, Ext JS, LLC.
43636 * Originally Released Under LGPL - original licence link has changed is not relivant.
43639 * <script type="text/javascript">
43643 * @class Roo.form.Radio
43644 * @extends Roo.form.Checkbox
43645 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
43646 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
43648 * Creates a new Radio
43649 * @param {Object} config Configuration options
43651 Roo.form.Radio = function(){
43652 Roo.form.Radio.superclass.constructor.apply(this, arguments);
43654 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
43655 inputType: 'radio',
43658 * If this radio is part of a group, it will return the selected value
43661 getGroupValue : function(){
43662 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
43666 onRender : function(ct, position){
43667 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
43669 if(this.inputValue !== undefined){
43670 this.el.dom.value = this.inputValue;
43673 this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
43674 //this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
43675 //var viewEl = this.wrap.createChild({
43676 // tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
43677 //this.viewEl = viewEl;
43678 //this.wrap.on('click', this.onClick, this);
43680 //this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
43681 //this.el.on('propertychange', this.setFromHidden, this); //ie
43686 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
43687 // viewEl.on('click', this.onClick, this);
43690 this.el.dom.checked = 'checked' ;
43696 });//<script type="text/javascript">
43699 * Based Ext JS Library 1.1.1
43700 * Copyright(c) 2006-2007, Ext JS, LLC.
43706 * @class Roo.HtmlEditorCore
43707 * @extends Roo.Component
43708 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
43710 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
43713 Roo.HtmlEditorCore = function(config){
43716 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
43721 * @event initialize
43722 * Fires when the editor is fully initialized (including the iframe)
43723 * @param {Roo.HtmlEditorCore} this
43728 * Fires when the editor is first receives the focus. Any insertion must wait
43729 * until after this event.
43730 * @param {Roo.HtmlEditorCore} this
43734 * @event beforesync
43735 * Fires before the textarea is updated with content from the editor iframe. Return false
43736 * to cancel the sync.
43737 * @param {Roo.HtmlEditorCore} this
43738 * @param {String} html
43742 * @event beforepush
43743 * Fires before the iframe editor is updated with content from the textarea. Return false
43744 * to cancel the push.
43745 * @param {Roo.HtmlEditorCore} this
43746 * @param {String} html
43751 * Fires when the textarea is updated with content from the editor iframe.
43752 * @param {Roo.HtmlEditorCore} this
43753 * @param {String} html
43758 * Fires when the iframe editor is updated with content from the textarea.
43759 * @param {Roo.HtmlEditorCore} this
43760 * @param {String} html
43765 * @event editorevent
43766 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
43767 * @param {Roo.HtmlEditorCore} this
43773 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
43775 // defaults : white / black...
43776 this.applyBlacklists();
43783 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
43787 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
43793 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
43798 * @cfg {Number} height (in pixels)
43802 * @cfg {Number} width (in pixels)
43807 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
43810 stylesheets: false,
43813 * @cfg {boolean} allowComments - default false - allow comments in HTML source - by default they are stripped - if you are editing email you may need this.
43815 allowComments: false,
43819 // private properties
43820 validationEvent : false,
43822 initialized : false,
43824 sourceEditMode : false,
43825 onFocus : Roo.emptyFn,
43827 hideMode:'offsets',
43831 // blacklist + whitelisted elements..
43838 * Protected method that will not generally be called directly. It
43839 * is called when the editor initializes the iframe with HTML contents. Override this method if you
43840 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
43842 getDocMarkup : function(){
43846 // inherit styels from page...??
43847 if (this.stylesheets === false) {
43849 Roo.get(document.head).select('style').each(function(node) {
43850 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
43853 Roo.get(document.head).select('link').each(function(node) {
43854 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
43857 } else if (!this.stylesheets.length) {
43859 st = '<style type="text/css">' +
43860 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
43863 for (var i in this.stylesheets) {
43864 st += '<link rel="stylesheet" href="' + this.stylesheets[i] +'" type="text/css">';
43869 st += '<style type="text/css">' +
43870 'IMG { cursor: pointer } ' +
43873 var cls = 'roo-htmleditor-body';
43875 if(this.bodyCls.length){
43876 cls += ' ' + this.bodyCls;
43879 return '<html><head>' + st +
43880 //<style type="text/css">' +
43881 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
43883 ' </head><body contenteditable="true" data-enable-grammerly="true" class="' + cls + '"></body></html>';
43887 onRender : function(ct, position)
43890 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
43891 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
43894 this.el.dom.style.border = '0 none';
43895 this.el.dom.setAttribute('tabIndex', -1);
43896 this.el.addClass('x-hidden hide');
43900 if(Roo.isIE){ // fix IE 1px bogus margin
43901 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
43905 this.frameId = Roo.id();
43909 var iframe = this.owner.wrap.createChild({
43911 cls: 'form-control', // bootstrap..
43913 name: this.frameId,
43914 frameBorder : 'no',
43915 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
43920 this.iframe = iframe.dom;
43922 this.assignDocWin();
43924 this.doc.designMode = 'on';
43927 this.doc.write(this.getDocMarkup());
43931 var task = { // must defer to wait for browser to be ready
43933 //console.log("run task?" + this.doc.readyState);
43934 this.assignDocWin();
43935 if(this.doc.body || this.doc.readyState == 'complete'){
43937 this.doc.designMode="on";
43941 Roo.TaskMgr.stop(task);
43942 this.initEditor.defer(10, this);
43949 Roo.TaskMgr.start(task);
43954 onResize : function(w, h)
43956 Roo.log('resize: ' +w + ',' + h );
43957 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
43961 if(typeof w == 'number'){
43963 this.iframe.style.width = w + 'px';
43965 if(typeof h == 'number'){
43967 this.iframe.style.height = h + 'px';
43969 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
43976 * Toggles the editor between standard and source edit mode.
43977 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
43979 toggleSourceEdit : function(sourceEditMode){
43981 this.sourceEditMode = sourceEditMode === true;
43983 if(this.sourceEditMode){
43985 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
43988 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
43989 //this.iframe.className = '';
43992 //this.setSize(this.owner.wrap.getSize());
43993 //this.fireEvent('editmodechange', this, this.sourceEditMode);
44000 * Protected method that will not generally be called directly. If you need/want
44001 * custom HTML cleanup, this is the method you should override.
44002 * @param {String} html The HTML to be cleaned
44003 * return {String} The cleaned HTML
44005 cleanHtml : function(html){
44006 html = String(html);
44007 if(html.length > 5){
44008 if(Roo.isSafari){ // strip safari nonsense
44009 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
44012 if(html == ' '){
44019 * HTML Editor -> Textarea
44020 * Protected method that will not generally be called directly. Syncs the contents
44021 * of the editor iframe with the textarea.
44023 syncValue : function(){
44024 if(this.initialized){
44025 var bd = (this.doc.body || this.doc.documentElement);
44026 //this.cleanUpPaste(); -- this is done else where and causes havoc..
44027 var html = bd.innerHTML;
44029 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
44030 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
44032 html = '<div style="'+m[0]+'">' + html + '</div>';
44035 html = this.cleanHtml(html);
44036 // fix up the special chars.. normaly like back quotes in word...
44037 // however we do not want to do this with chinese..
44038 html = html.replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]|[\u0080-\uFFFF]/g, function(match) {
44040 var cc = match.charCodeAt();
44042 // Get the character value, handling surrogate pairs
44043 if (match.length == 2) {
44044 // It's a surrogate pair, calculate the Unicode code point
44045 var high = match.charCodeAt(0) - 0xD800;
44046 var low = match.charCodeAt(1) - 0xDC00;
44047 cc = (high * 0x400) + low + 0x10000;
44049 (cc >= 0x4E00 && cc < 0xA000 ) ||
44050 (cc >= 0x3400 && cc < 0x4E00 ) ||
44051 (cc >= 0xf900 && cc < 0xfb00 )
44056 // No, use a numeric entity. Here we brazenly (and possibly mistakenly)
44057 return "&#" + cc + ";";
44064 if(this.owner.fireEvent('beforesync', this, html) !== false){
44065 this.el.dom.value = html;
44066 this.owner.fireEvent('sync', this, html);
44072 * Protected method that will not generally be called directly. Pushes the value of the textarea
44073 * into the iframe editor.
44075 pushValue : function(){
44076 if(this.initialized){
44077 var v = this.el.dom.value.trim();
44079 // if(v.length < 1){
44083 if(this.owner.fireEvent('beforepush', this, v) !== false){
44084 var d = (this.doc.body || this.doc.documentElement);
44086 this.cleanUpPaste();
44087 this.el.dom.value = d.innerHTML;
44088 this.owner.fireEvent('push', this, v);
44094 deferFocus : function(){
44095 this.focus.defer(10, this);
44099 focus : function(){
44100 if(this.win && !this.sourceEditMode){
44107 assignDocWin: function()
44109 var iframe = this.iframe;
44112 this.doc = iframe.contentWindow.document;
44113 this.win = iframe.contentWindow;
44115 // if (!Roo.get(this.frameId)) {
44118 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
44119 // this.win = Roo.get(this.frameId).dom.contentWindow;
44121 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
44125 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
44126 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
44131 initEditor : function(){
44132 //console.log("INIT EDITOR");
44133 this.assignDocWin();
44137 this.doc.designMode="on";
44139 this.doc.write(this.getDocMarkup());
44142 var dbody = (this.doc.body || this.doc.documentElement);
44143 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
44144 // this copies styles from the containing element into thsi one..
44145 // not sure why we need all of this..
44146 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
44148 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
44149 //ss['background-attachment'] = 'fixed'; // w3c
44150 dbody.bgProperties = 'fixed'; // ie
44151 //Roo.DomHelper.applyStyles(dbody, ss);
44152 Roo.EventManager.on(this.doc, {
44153 //'mousedown': this.onEditorEvent,
44154 'mouseup': this.onEditorEvent,
44155 'dblclick': this.onEditorEvent,
44156 'click': this.onEditorEvent,
44157 'keyup': this.onEditorEvent,
44162 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
44164 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
44165 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
44167 this.initialized = true;
44169 this.owner.fireEvent('initialize', this);
44174 onDestroy : function(){
44180 //for (var i =0; i < this.toolbars.length;i++) {
44181 // // fixme - ask toolbars for heights?
44182 // this.toolbars[i].onDestroy();
44185 //this.wrap.dom.innerHTML = '';
44186 //this.wrap.remove();
44191 onFirstFocus : function(){
44193 this.assignDocWin();
44196 this.activated = true;
44199 if(Roo.isGecko){ // prevent silly gecko errors
44201 var s = this.win.getSelection();
44202 if(!s.focusNode || s.focusNode.nodeType != 3){
44203 var r = s.getRangeAt(0);
44204 r.selectNodeContents((this.doc.body || this.doc.documentElement));
44209 this.execCmd('useCSS', true);
44210 this.execCmd('styleWithCSS', false);
44213 this.owner.fireEvent('activate', this);
44217 adjustFont: function(btn){
44218 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
44219 //if(Roo.isSafari){ // safari
44222 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
44223 if(Roo.isSafari){ // safari
44224 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
44225 v = (v < 10) ? 10 : v;
44226 v = (v > 48) ? 48 : v;
44227 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
44232 v = Math.max(1, v+adjust);
44234 this.execCmd('FontSize', v );
44237 onEditorEvent : function(e)
44239 this.owner.fireEvent('editorevent', this, e);
44240 // this.updateToolbar();
44241 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
44244 insertTag : function(tg)
44246 // could be a bit smarter... -> wrap the current selected tRoo..
44247 if (tg.toLowerCase() == 'span' ||
44248 tg.toLowerCase() == 'code' ||
44249 tg.toLowerCase() == 'sup' ||
44250 tg.toLowerCase() == 'sub'
44253 range = this.createRange(this.getSelection());
44254 var wrappingNode = this.doc.createElement(tg.toLowerCase());
44255 wrappingNode.appendChild(range.extractContents());
44256 range.insertNode(wrappingNode);
44263 this.execCmd("formatblock", tg);
44267 insertText : function(txt)
44271 var range = this.createRange();
44272 range.deleteContents();
44273 //alert(Sender.getAttribute('label'));
44275 range.insertNode(this.doc.createTextNode(txt));
44281 * Executes a Midas editor command on the editor document and performs necessary focus and
44282 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
44283 * @param {String} cmd The Midas command
44284 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
44286 relayCmd : function(cmd, value){
44288 this.execCmd(cmd, value);
44289 this.owner.fireEvent('editorevent', this);
44290 //this.updateToolbar();
44291 this.owner.deferFocus();
44295 * Executes a Midas editor command directly on the editor document.
44296 * For visual commands, you should use {@link #relayCmd} instead.
44297 * <b>This should only be called after the editor is initialized.</b>
44298 * @param {String} cmd The Midas command
44299 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
44301 execCmd : function(cmd, value){
44302 this.doc.execCommand(cmd, false, value === undefined ? null : value);
44309 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
44311 * @param {String} text | dom node..
44313 insertAtCursor : function(text)
44316 if(!this.activated){
44322 var r = this.doc.selection.createRange();
44333 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
44337 // from jquery ui (MIT licenced)
44339 var win = this.win;
44341 if (win.getSelection && win.getSelection().getRangeAt) {
44342 range = win.getSelection().getRangeAt(0);
44343 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
44344 range.insertNode(node);
44345 } else if (win.document.selection && win.document.selection.createRange) {
44346 // no firefox support
44347 var txt = typeof(text) == 'string' ? text : text.outerHTML;
44348 win.document.selection.createRange().pasteHTML(txt);
44350 // no firefox support
44351 var txt = typeof(text) == 'string' ? text : text.outerHTML;
44352 this.execCmd('InsertHTML', txt);
44361 mozKeyPress : function(e){
44363 var c = e.getCharCode(), cmd;
44366 c = String.fromCharCode(c).toLowerCase();
44380 this.cleanUpPaste.defer(100, this);
44388 e.preventDefault();
44396 fixKeys : function(){ // load time branching for fastest keydown performance
44398 return function(e){
44399 var k = e.getKey(), r;
44402 r = this.doc.selection.createRange();
44405 r.pasteHTML('    ');
44412 r = this.doc.selection.createRange();
44414 var target = r.parentElement();
44415 if(!target || target.tagName.toLowerCase() != 'li'){
44417 r.pasteHTML('<br />');
44423 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
44424 this.cleanUpPaste.defer(100, this);
44430 }else if(Roo.isOpera){
44431 return function(e){
44432 var k = e.getKey();
44436 this.execCmd('InsertHTML','    ');
44439 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
44440 this.cleanUpPaste.defer(100, this);
44445 }else if(Roo.isSafari){
44446 return function(e){
44447 var k = e.getKey();
44451 this.execCmd('InsertText','\t');
44455 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
44456 this.cleanUpPaste.defer(100, this);
44464 getAllAncestors: function()
44466 var p = this.getSelectedNode();
44469 a.push(p); // push blank onto stack..
44470 p = this.getParentElement();
44474 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
44478 a.push(this.doc.body);
44482 lastSelNode : false,
44485 getSelection : function()
44487 this.assignDocWin();
44488 return Roo.isIE ? this.doc.selection : this.win.getSelection();
44491 getSelectedNode: function()
44493 // this may only work on Gecko!!!
44495 // should we cache this!!!!
44500 var range = this.createRange(this.getSelection()).cloneRange();
44503 var parent = range.parentElement();
44505 var testRange = range.duplicate();
44506 testRange.moveToElementText(parent);
44507 if (testRange.inRange(range)) {
44510 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
44513 parent = parent.parentElement;
44518 // is ancestor a text element.
44519 var ac = range.commonAncestorContainer;
44520 if (ac.nodeType == 3) {
44521 ac = ac.parentNode;
44524 var ar = ac.childNodes;
44527 var other_nodes = [];
44528 var has_other_nodes = false;
44529 for (var i=0;i<ar.length;i++) {
44530 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
44533 // fullly contained node.
44535 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
44540 // probably selected..
44541 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
44542 other_nodes.push(ar[i]);
44546 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
44551 has_other_nodes = true;
44553 if (!nodes.length && other_nodes.length) {
44554 nodes= other_nodes;
44556 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
44562 createRange: function(sel)
44564 // this has strange effects when using with
44565 // top toolbar - not sure if it's a great idea.
44566 //this.editor.contentWindow.focus();
44567 if (typeof sel != "undefined") {
44569 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
44571 return this.doc.createRange();
44574 return this.doc.createRange();
44577 getParentElement: function()
44580 this.assignDocWin();
44581 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
44583 var range = this.createRange(sel);
44586 var p = range.commonAncestorContainer;
44587 while (p.nodeType == 3) { // text node
44598 * Range intersection.. the hard stuff...
44602 * [ -- selected range --- ]
44606 * if end is before start or hits it. fail.
44607 * if start is after end or hits it fail.
44609 * if either hits (but other is outside. - then it's not
44615 // @see http://www.thismuchiknow.co.uk/?p=64.
44616 rangeIntersectsNode : function(range, node)
44618 var nodeRange = node.ownerDocument.createRange();
44620 nodeRange.selectNode(node);
44622 nodeRange.selectNodeContents(node);
44625 var rangeStartRange = range.cloneRange();
44626 rangeStartRange.collapse(true);
44628 var rangeEndRange = range.cloneRange();
44629 rangeEndRange.collapse(false);
44631 var nodeStartRange = nodeRange.cloneRange();
44632 nodeStartRange.collapse(true);
44634 var nodeEndRange = nodeRange.cloneRange();
44635 nodeEndRange.collapse(false);
44637 return rangeStartRange.compareBoundaryPoints(
44638 Range.START_TO_START, nodeEndRange) == -1 &&
44639 rangeEndRange.compareBoundaryPoints(
44640 Range.START_TO_START, nodeStartRange) == 1;
44644 rangeCompareNode : function(range, node)
44646 var nodeRange = node.ownerDocument.createRange();
44648 nodeRange.selectNode(node);
44650 nodeRange.selectNodeContents(node);
44654 range.collapse(true);
44656 nodeRange.collapse(true);
44658 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
44659 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
44661 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
44663 var nodeIsBefore = ss == 1;
44664 var nodeIsAfter = ee == -1;
44666 if (nodeIsBefore && nodeIsAfter) {
44669 if (!nodeIsBefore && nodeIsAfter) {
44670 return 1; //right trailed.
44673 if (nodeIsBefore && !nodeIsAfter) {
44674 return 2; // left trailed.
44680 // private? - in a new class?
44681 cleanUpPaste : function()
44683 // cleans up the whole document..
44684 Roo.log('cleanuppaste');
44686 this.cleanUpChildren(this.doc.body);
44687 var clean = this.cleanWordChars(this.doc.body.innerHTML);
44688 if (clean != this.doc.body.innerHTML) {
44689 this.doc.body.innerHTML = clean;
44694 cleanWordChars : function(input) {// change the chars to hex code
44695 var he = Roo.HtmlEditorCore;
44697 var output = input;
44698 Roo.each(he.swapCodes, function(sw) {
44699 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
44701 output = output.replace(swapper, sw[1]);
44708 cleanUpChildren : function (n)
44710 if (!n.childNodes.length) {
44713 for (var i = n.childNodes.length-1; i > -1 ; i--) {
44714 this.cleanUpChild(n.childNodes[i]);
44721 cleanUpChild : function (node)
44724 //console.log(node);
44725 if (node.nodeName == "#text") {
44726 // clean up silly Windows -- stuff?
44729 if (node.nodeName == "#comment") {
44730 if (!this.allowComments) {
44731 node.parentNode.removeChild(node);
44733 // clean up silly Windows -- stuff?
44736 var lcname = node.tagName.toLowerCase();
44737 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
44738 // whitelist of tags..
44740 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
44742 node.parentNode.removeChild(node);
44747 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
44749 // spans with no attributes - just remove them..
44750 if ((!node.attributes || !node.attributes.length) && lcname == 'span') {
44751 remove_keep_children = true;
44754 // remove <a name=....> as rendering on yahoo mailer is borked with this.
44755 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
44757 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
44758 // remove_keep_children = true;
44761 if (remove_keep_children) {
44762 this.cleanUpChildren(node);
44763 // inserts everything just before this node...
44764 while (node.childNodes.length) {
44765 var cn = node.childNodes[0];
44766 node.removeChild(cn);
44767 node.parentNode.insertBefore(cn, node);
44769 node.parentNode.removeChild(node);
44773 if (!node.attributes || !node.attributes.length) {
44778 this.cleanUpChildren(node);
44782 function cleanAttr(n,v)
44785 if (v.match(/^\./) || v.match(/^\//)) {
44788 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/) || v.match(/^ftp:/)) {
44791 if (v.match(/^#/)) {
44794 if (v.match(/^\{/)) { // allow template editing.
44797 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
44798 node.removeAttribute(n);
44802 var cwhite = this.cwhite;
44803 var cblack = this.cblack;
44805 function cleanStyle(n,v)
44807 if (v.match(/expression/)) { //XSS?? should we even bother..
44808 node.removeAttribute(n);
44812 var parts = v.split(/;/);
44815 Roo.each(parts, function(p) {
44816 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
44820 var l = p.split(':').shift().replace(/\s+/g,'');
44821 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
44823 if ( cwhite.length && cblack.indexOf(l) > -1) {
44824 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
44825 //node.removeAttribute(n);
44829 // only allow 'c whitelisted system attributes'
44830 if ( cwhite.length && cwhite.indexOf(l) < 0) {
44831 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
44832 //node.removeAttribute(n);
44842 if (clean.length) {
44843 node.setAttribute(n, clean.join(';'));
44845 node.removeAttribute(n);
44851 for (var i = node.attributes.length-1; i > -1 ; i--) {
44852 var a = node.attributes[i];
44855 if (a.name.toLowerCase().substr(0,2)=='on') {
44856 node.removeAttribute(a.name);
44859 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
44860 node.removeAttribute(a.name);
44863 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
44864 cleanAttr(a.name,a.value); // fixme..
44867 if (a.name == 'style') {
44868 cleanStyle(a.name,a.value);
44871 /// clean up MS crap..
44872 // tecnically this should be a list of valid class'es..
44875 if (a.name == 'class') {
44876 if (a.value.match(/^Mso/)) {
44877 node.removeAttribute('class');
44880 if (a.value.match(/^body$/)) {
44881 node.removeAttribute('class');
44892 this.cleanUpChildren(node);
44898 * Clean up MS wordisms...
44900 cleanWord : function(node)
44903 this.cleanWord(this.doc.body);
44908 node.nodeName == 'SPAN' &&
44909 !node.hasAttributes() &&
44910 node.childNodes.length == 1 &&
44911 node.firstChild.nodeName == "#text"
44913 var textNode = node.firstChild;
44914 node.removeChild(textNode);
44915 if (node.getAttribute('lang') != 'zh-CN') { // do not space pad on chinese characters..
44916 node.parentNode.insertBefore(node.ownerDocument.createTextNode(" "), node);
44918 node.parentNode.insertBefore(textNode, node);
44919 if (node.getAttribute('lang') != 'zh-CN') { // do not space pad on chinese characters..
44920 node.parentNode.insertBefore(node.ownerDocument.createTextNode(" ") , node);
44922 node.parentNode.removeChild(node);
44925 if (node.nodeName == "#text") {
44926 // clean up silly Windows -- stuff?
44929 if (node.nodeName == "#comment") {
44930 node.parentNode.removeChild(node);
44931 // clean up silly Windows -- stuff?
44935 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
44936 node.parentNode.removeChild(node);
44939 //Roo.log(node.tagName);
44940 // remove - but keep children..
44941 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|v:|font)/)) {
44942 //Roo.log('-- removed');
44943 while (node.childNodes.length) {
44944 var cn = node.childNodes[0];
44945 node.removeChild(cn);
44946 node.parentNode.insertBefore(cn, node);
44947 // move node to parent - and clean it..
44948 this.cleanWord(cn);
44950 node.parentNode.removeChild(node);
44951 /// no need to iterate chidlren = it's got none..
44952 //this.iterateChildren(node, this.cleanWord);
44956 if (node.className.length) {
44958 var cn = node.className.split(/\W+/);
44960 Roo.each(cn, function(cls) {
44961 if (cls.match(/Mso[a-zA-Z]+/)) {
44966 node.className = cna.length ? cna.join(' ') : '';
44968 node.removeAttribute("class");
44972 if (node.hasAttribute("lang")) {
44973 node.removeAttribute("lang");
44976 if (node.hasAttribute("style")) {
44978 var styles = node.getAttribute("style").split(";");
44980 Roo.each(styles, function(s) {
44981 if (!s.match(/:/)) {
44984 var kv = s.split(":");
44985 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
44988 // what ever is left... we allow.
44991 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
44992 if (!nstyle.length) {
44993 node.removeAttribute('style');
44996 this.iterateChildren(node, this.cleanWord);
45002 * iterateChildren of a Node, calling fn each time, using this as the scole..
45003 * @param {DomNode} node node to iterate children of.
45004 * @param {Function} fn method of this class to call on each item.
45006 iterateChildren : function(node, fn)
45008 if (!node.childNodes.length) {
45011 for (var i = node.childNodes.length-1; i > -1 ; i--) {
45012 fn.call(this, node.childNodes[i])
45018 * cleanTableWidths.
45020 * Quite often pasting from word etc.. results in tables with column and widths.
45021 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
45024 cleanTableWidths : function(node)
45029 this.cleanTableWidths(this.doc.body);
45034 if (node.nodeName == "#text" || node.nodeName == "#comment") {
45037 Roo.log(node.tagName);
45038 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
45039 this.iterateChildren(node, this.cleanTableWidths);
45042 if (node.hasAttribute('width')) {
45043 node.removeAttribute('width');
45047 if (node.hasAttribute("style")) {
45050 var styles = node.getAttribute("style").split(";");
45052 Roo.each(styles, function(s) {
45053 if (!s.match(/:/)) {
45056 var kv = s.split(":");
45057 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
45060 // what ever is left... we allow.
45063 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
45064 if (!nstyle.length) {
45065 node.removeAttribute('style');
45069 this.iterateChildren(node, this.cleanTableWidths);
45077 domToHTML : function(currentElement, depth, nopadtext) {
45079 depth = depth || 0;
45080 nopadtext = nopadtext || false;
45082 if (!currentElement) {
45083 return this.domToHTML(this.doc.body);
45086 //Roo.log(currentElement);
45088 var allText = false;
45089 var nodeName = currentElement.nodeName;
45090 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
45092 if (nodeName == '#text') {
45094 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
45099 if (nodeName != 'BODY') {
45102 // Prints the node tagName, such as <A>, <IMG>, etc
45105 for(i = 0; i < currentElement.attributes.length;i++) {
45107 var aname = currentElement.attributes.item(i).name;
45108 if (!currentElement.attributes.item(i).value.length) {
45111 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
45114 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
45123 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
45126 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
45131 // Traverse the tree
45133 var currentElementChild = currentElement.childNodes.item(i);
45134 var allText = true;
45135 var innerHTML = '';
45137 while (currentElementChild) {
45138 // Formatting code (indent the tree so it looks nice on the screen)
45139 var nopad = nopadtext;
45140 if (lastnode == 'SPAN') {
45144 if (currentElementChild.nodeName == '#text') {
45145 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
45146 toadd = nopadtext ? toadd : toadd.trim();
45147 if (!nopad && toadd.length > 80) {
45148 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
45150 innerHTML += toadd;
45153 currentElementChild = currentElement.childNodes.item(i);
45159 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
45161 // Recursively traverse the tree structure of the child node
45162 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
45163 lastnode = currentElementChild.nodeName;
45165 currentElementChild=currentElement.childNodes.item(i);
45171 // The remaining code is mostly for formatting the tree
45172 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
45177 ret+= "</"+tagName+">";
45183 applyBlacklists : function()
45185 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
45186 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
45190 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
45191 if (b.indexOf(tag) > -1) {
45194 this.white.push(tag);
45198 Roo.each(w, function(tag) {
45199 if (b.indexOf(tag) > -1) {
45202 if (this.white.indexOf(tag) > -1) {
45205 this.white.push(tag);
45210 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
45211 if (w.indexOf(tag) > -1) {
45214 this.black.push(tag);
45218 Roo.each(b, function(tag) {
45219 if (w.indexOf(tag) > -1) {
45222 if (this.black.indexOf(tag) > -1) {
45225 this.black.push(tag);
45230 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
45231 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
45235 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
45236 if (b.indexOf(tag) > -1) {
45239 this.cwhite.push(tag);
45243 Roo.each(w, function(tag) {
45244 if (b.indexOf(tag) > -1) {
45247 if (this.cwhite.indexOf(tag) > -1) {
45250 this.cwhite.push(tag);
45255 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
45256 if (w.indexOf(tag) > -1) {
45259 this.cblack.push(tag);
45263 Roo.each(b, function(tag) {
45264 if (w.indexOf(tag) > -1) {
45267 if (this.cblack.indexOf(tag) > -1) {
45270 this.cblack.push(tag);
45275 setStylesheets : function(stylesheets)
45277 if(typeof(stylesheets) == 'string'){
45278 Roo.get(this.iframe.contentDocument.head).createChild({
45280 rel : 'stylesheet',
45289 Roo.each(stylesheets, function(s) {
45294 Roo.get(_this.iframe.contentDocument.head).createChild({
45296 rel : 'stylesheet',
45305 removeStylesheets : function()
45309 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
45314 setStyle : function(style)
45316 Roo.get(this.iframe.contentDocument.head).createChild({
45325 // hide stuff that is not compatible
45339 * @event specialkey
45343 * @cfg {String} fieldClass @hide
45346 * @cfg {String} focusClass @hide
45349 * @cfg {String} autoCreate @hide
45352 * @cfg {String} inputType @hide
45355 * @cfg {String} invalidClass @hide
45358 * @cfg {String} invalidText @hide
45361 * @cfg {String} msgFx @hide
45364 * @cfg {String} validateOnBlur @hide
45368 Roo.HtmlEditorCore.white = [
45369 'area', 'br', 'img', 'input', 'hr', 'wbr',
45371 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
45372 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
45373 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
45374 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
45375 'table', 'ul', 'xmp',
45377 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
45380 'dir', 'menu', 'ol', 'ul', 'dl',
45386 Roo.HtmlEditorCore.black = [
45387 // 'embed', 'object', // enable - backend responsiblity to clean thiese
45389 'base', 'basefont', 'bgsound', 'blink', 'body',
45390 'frame', 'frameset', 'head', 'html', 'ilayer',
45391 'iframe', 'layer', 'link', 'meta', 'object',
45392 'script', 'style' ,'title', 'xml' // clean later..
45394 Roo.HtmlEditorCore.clean = [
45395 'script', 'style', 'title', 'xml'
45397 Roo.HtmlEditorCore.remove = [
45402 Roo.HtmlEditorCore.ablack = [
45406 Roo.HtmlEditorCore.aclean = [
45407 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
45411 Roo.HtmlEditorCore.pwhite= [
45412 'http', 'https', 'mailto'
45415 // white listed style attributes.
45416 Roo.HtmlEditorCore.cwhite= [
45417 // 'text-align', /// default is to allow most things..
45423 // black listed style attributes.
45424 Roo.HtmlEditorCore.cblack= [
45425 // 'font-size' -- this can be set by the project
45429 Roo.HtmlEditorCore.swapCodes =[
45430 [ 8211, "–" ],
45431 [ 8212, "—" ],
45440 //<script type="text/javascript">
45443 * Ext JS Library 1.1.1
45444 * Copyright(c) 2006-2007, Ext JS, LLC.
45450 Roo.form.HtmlEditor = function(config){
45454 Roo.form.HtmlEditor.superclass.constructor.call(this, config);
45456 if (!this.toolbars) {
45457 this.toolbars = [];
45459 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
45465 * @class Roo.form.HtmlEditor
45466 * @extends Roo.form.Field
45467 * Provides a lightweight HTML Editor component.
45469 * This has been tested on Fireforx / Chrome.. IE may not be so great..
45471 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
45472 * supported by this editor.</b><br/><br/>
45473 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
45474 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
45476 Roo.extend(Roo.form.HtmlEditor, Roo.form.Field, {
45478 * @cfg {Boolean} clearUp
45482 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
45487 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
45492 * @cfg {Number} height (in pixels)
45496 * @cfg {Number} width (in pixels)
45501 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
45504 stylesheets: false,
45508 * @cfg {Array} blacklist of css styles style attributes (blacklist overrides whitelist)
45513 * @cfg {Array} whitelist of css styles style attributes (blacklist overrides whitelist)
45519 * @cfg {Array} blacklist of html tags - in addition to standard blacklist.
45524 * @cfg {Array} whitelist of html tags - in addition to statndard whitelist
45529 * @cfg {boolean} allowComments - default false - allow comments in HTML source - by default they are stripped - if you are editing email you may need this.
45531 allowComments: false,
45536 // private properties
45537 validationEvent : false,
45539 initialized : false,
45542 onFocus : Roo.emptyFn,
45544 hideMode:'offsets',
45546 actionMode : 'container', // defaults to hiding it...
45548 defaultAutoCreate : { // modified by initCompnoent..
45550 style:"width:500px;height:300px;",
45551 autocomplete: "new-password"
45555 initComponent : function(){
45558 * @event initialize
45559 * Fires when the editor is fully initialized (including the iframe)
45560 * @param {HtmlEditor} this
45565 * Fires when the editor is first receives the focus. Any insertion must wait
45566 * until after this event.
45567 * @param {HtmlEditor} this
45571 * @event beforesync
45572 * Fires before the textarea is updated with content from the editor iframe. Return false
45573 * to cancel the sync.
45574 * @param {HtmlEditor} this
45575 * @param {String} html
45579 * @event beforepush
45580 * Fires before the iframe editor is updated with content from the textarea. Return false
45581 * to cancel the push.
45582 * @param {HtmlEditor} this
45583 * @param {String} html
45588 * Fires when the textarea is updated with content from the editor iframe.
45589 * @param {HtmlEditor} this
45590 * @param {String} html
45595 * Fires when the iframe editor is updated with content from the textarea.
45596 * @param {HtmlEditor} this
45597 * @param {String} html
45601 * @event editmodechange
45602 * Fires when the editor switches edit modes
45603 * @param {HtmlEditor} this
45604 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
45606 editmodechange: true,
45608 * @event editorevent
45609 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
45610 * @param {HtmlEditor} this
45614 * @event firstfocus
45615 * Fires when on first focus - needed by toolbars..
45616 * @param {HtmlEditor} this
45621 * Auto save the htmlEditor value as a file into Events
45622 * @param {HtmlEditor} this
45626 * @event savedpreview
45627 * preview the saved version of htmlEditor
45628 * @param {HtmlEditor} this
45630 savedpreview: true,
45633 * @event stylesheetsclick
45634 * Fires when press the Sytlesheets button
45635 * @param {Roo.HtmlEditorCore} this
45637 stylesheetsclick: true
45639 this.defaultAutoCreate = {
45641 style:'width: ' + this.width + 'px;height: ' + this.height + 'px;',
45642 autocomplete: "new-password"
45647 * Protected method that will not generally be called directly. It
45648 * is called when the editor creates its toolbar. Override this method if you need to
45649 * add custom toolbar buttons.
45650 * @param {HtmlEditor} editor
45652 createToolbar : function(editor){
45653 Roo.log("create toolbars");
45654 if (!editor.toolbars || !editor.toolbars.length) {
45655 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
45658 for (var i =0 ; i < editor.toolbars.length;i++) {
45659 editor.toolbars[i] = Roo.factory(
45660 typeof(editor.toolbars[i]) == 'string' ?
45661 { xtype: editor.toolbars[i]} : editor.toolbars[i],
45662 Roo.form.HtmlEditor);
45663 editor.toolbars[i].init(editor);
45671 onRender : function(ct, position)
45674 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
45676 this.wrap = this.el.wrap({
45677 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
45680 this.editorcore.onRender(ct, position);
45682 if (this.resizable) {
45683 this.resizeEl = new Roo.Resizable(this.wrap, {
45687 minHeight : this.height,
45688 height: this.height,
45689 handles : this.resizable,
45692 resize : function(r, w, h) {
45693 _t.onResize(w,h); // -something
45699 this.createToolbar(this);
45703 this.setSize(this.wrap.getSize());
45705 if (this.resizeEl) {
45706 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
45707 // should trigger onReize..
45710 this.keyNav = new Roo.KeyNav(this.el, {
45712 "tab" : function(e){
45713 e.preventDefault();
45715 var value = this.getValue();
45717 var start = this.el.dom.selectionStart;
45718 var end = this.el.dom.selectionEnd;
45722 this.setValue(value.substring(0, start) + "\t" + value.substring(end));
45723 this.el.dom.setSelectionRange(end + 1, end + 1);
45727 var f = value.substring(0, start).split("\t");
45729 if(f.pop().length != 0){
45733 this.setValue(f.join("\t") + value.substring(end));
45734 this.el.dom.setSelectionRange(start - 1, start - 1);
45738 "home" : function(e){
45739 e.preventDefault();
45741 var curr = this.el.dom.selectionStart;
45742 var lines = this.getValue().split("\n");
45749 this.el.dom.setSelectionRange(0, 0);
45755 for (var i = 0; i < lines.length;i++) {
45756 pos += lines[i].length;
45766 pos -= lines[i].length;
45772 this.el.dom.setSelectionRange(pos, pos);
45776 this.el.dom.selectionStart = pos;
45777 this.el.dom.selectionEnd = curr;
45780 "end" : function(e){
45781 e.preventDefault();
45783 var curr = this.el.dom.selectionStart;
45784 var lines = this.getValue().split("\n");
45791 this.el.dom.setSelectionRange(this.getValue().length, this.getValue().length);
45797 for (var i = 0; i < lines.length;i++) {
45799 pos += lines[i].length;
45813 this.el.dom.setSelectionRange(pos, pos);
45817 this.el.dom.selectionStart = curr;
45818 this.el.dom.selectionEnd = pos;
45823 doRelay : function(foo, bar, hname){
45824 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
45830 // if(this.autosave && this.w){
45831 // this.autoSaveFn = setInterval(this.autosave, 1000);
45836 onResize : function(w, h)
45838 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
45843 if(typeof w == 'number'){
45844 var aw = w - this.wrap.getFrameWidth('lr');
45845 this.el.setWidth(this.adjustWidth('textarea', aw));
45848 if(typeof h == 'number'){
45850 for (var i =0; i < this.toolbars.length;i++) {
45851 // fixme - ask toolbars for heights?
45852 tbh += this.toolbars[i].tb.el.getHeight();
45853 if (this.toolbars[i].footer) {
45854 tbh += this.toolbars[i].footer.el.getHeight();
45861 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
45862 ah -= 5; // knock a few pixes off for look..
45864 this.el.setHeight(this.adjustWidth('textarea', ah));
45868 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
45869 this.editorcore.onResize(ew,eh);
45874 * Toggles the editor between standard and source edit mode.
45875 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
45877 toggleSourceEdit : function(sourceEditMode)
45879 this.editorcore.toggleSourceEdit(sourceEditMode);
45881 if(this.editorcore.sourceEditMode){
45882 Roo.log('editor - showing textarea');
45885 // Roo.log(this.syncValue());
45886 this.editorcore.syncValue();
45887 this.el.removeClass('x-hidden');
45888 this.el.dom.removeAttribute('tabIndex');
45891 for (var i = 0; i < this.toolbars.length; i++) {
45892 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
45893 this.toolbars[i].tb.hide();
45894 this.toolbars[i].footer.hide();
45899 Roo.log('editor - hiding textarea');
45901 // Roo.log(this.pushValue());
45902 this.editorcore.pushValue();
45904 this.el.addClass('x-hidden');
45905 this.el.dom.setAttribute('tabIndex', -1);
45907 for (var i = 0; i < this.toolbars.length; i++) {
45908 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
45909 this.toolbars[i].tb.show();
45910 this.toolbars[i].footer.show();
45914 //this.deferFocus();
45917 this.setSize(this.wrap.getSize());
45918 this.onResize(this.wrap.getSize().width, this.wrap.getSize().height);
45920 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
45923 // private (for BoxComponent)
45924 adjustSize : Roo.BoxComponent.prototype.adjustSize,
45926 // private (for BoxComponent)
45927 getResizeEl : function(){
45931 // private (for BoxComponent)
45932 getPositionEl : function(){
45937 initEvents : function(){
45938 this.originalValue = this.getValue();
45942 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
45945 markInvalid : Roo.emptyFn,
45947 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
45950 clearInvalid : Roo.emptyFn,
45952 setValue : function(v){
45953 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
45954 this.editorcore.pushValue();
45959 deferFocus : function(){
45960 this.focus.defer(10, this);
45964 focus : function(){
45965 this.editorcore.focus();
45971 onDestroy : function(){
45977 for (var i =0; i < this.toolbars.length;i++) {
45978 // fixme - ask toolbars for heights?
45979 this.toolbars[i].onDestroy();
45982 this.wrap.dom.innerHTML = '';
45983 this.wrap.remove();
45988 onFirstFocus : function(){
45989 //Roo.log("onFirstFocus");
45990 this.editorcore.onFirstFocus();
45991 for (var i =0; i < this.toolbars.length;i++) {
45992 this.toolbars[i].onFirstFocus();
45998 syncValue : function()
46000 this.editorcore.syncValue();
46003 pushValue : function()
46005 this.editorcore.pushValue();
46008 setStylesheets : function(stylesheets)
46010 this.editorcore.setStylesheets(stylesheets);
46013 removeStylesheets : function()
46015 this.editorcore.removeStylesheets();
46019 // hide stuff that is not compatible
46033 * @event specialkey
46037 * @cfg {String} fieldClass @hide
46040 * @cfg {String} focusClass @hide
46043 * @cfg {String} autoCreate @hide
46046 * @cfg {String} inputType @hide
46049 * @cfg {String} invalidClass @hide
46052 * @cfg {String} invalidText @hide
46055 * @cfg {String} msgFx @hide
46058 * @cfg {String} validateOnBlur @hide
46062 // <script type="text/javascript">
46065 * Ext JS Library 1.1.1
46066 * Copyright(c) 2006-2007, Ext JS, LLC.
46072 * @class Roo.form.HtmlEditorToolbar1
46077 new Roo.form.HtmlEditor({
46080 new Roo.form.HtmlEditorToolbar1({
46081 disable : { fonts: 1 , format: 1, ..., ... , ...],
46087 * @cfg {Object} disable List of elements to disable..
46088 * @cfg {Array} btns List of additional buttons.
46092 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
46095 Roo.form.HtmlEditor.ToolbarStandard = function(config)
46098 Roo.apply(this, config);
46100 // default disabled, based on 'good practice'..
46101 this.disable = this.disable || {};
46102 Roo.applyIf(this.disable, {
46105 specialElements : true
46109 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
46110 // dont call parent... till later.
46113 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
46120 editorcore : false,
46122 * @cfg {Object} disable List of toolbar elements to disable
46129 * @cfg {String} createLinkText The default text for the create link prompt
46131 createLinkText : 'Please enter the URL for the link:',
46133 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
46135 defaultLinkValue : 'http:/'+'/',
46139 * @cfg {Array} fontFamilies An array of available font families
46157 // "á" , ?? a acute?
46162 "°" // , // degrees
46164 // "é" , // e ecute
46165 // "ú" , // u ecute?
46168 specialElements : [
46170 text: "Insert Table",
46173 ihtml : '<table><tr><td>Cell</td></tr></table>'
46177 text: "Insert Image",
46180 ihtml : '<img src="about:blank"/>'
46189 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
46190 "input:submit", "input:button", "select", "textarea", "label" ],
46193 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
46195 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"],
46204 * @cfg {String} defaultFont default font to use.
46206 defaultFont: 'tahoma',
46208 fontSelect : false,
46211 formatCombo : false,
46213 init : function(editor)
46215 this.editor = editor;
46216 this.editorcore = editor.editorcore ? editor.editorcore : editor;
46217 var editorcore = this.editorcore;
46221 var fid = editorcore.frameId;
46223 function btn(id, toggle, handler){
46224 var xid = fid + '-'+ id ;
46228 cls : 'x-btn-icon x-edit-'+id,
46229 enableToggle:toggle !== false,
46230 scope: _t, // was editor...
46231 handler:handler||_t.relayBtnCmd,
46232 clickEvent:'mousedown',
46233 tooltip: etb.buttonTips[id] || undefined, ///tips ???
46240 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
46242 // stop form submits
46243 tb.el.on('click', function(e){
46244 e.preventDefault(); // what does this do?
46247 if(!this.disable.font) { // && !Roo.isSafari){
46248 /* why no safari for fonts
46249 editor.fontSelect = tb.el.createChild({
46252 cls:'x-font-select',
46253 html: this.createFontOptions()
46256 editor.fontSelect.on('change', function(){
46257 var font = editor.fontSelect.dom.value;
46258 editor.relayCmd('fontname', font);
46259 editor.deferFocus();
46263 editor.fontSelect.dom,
46269 if(!this.disable.formats){
46270 this.formatCombo = new Roo.form.ComboBox({
46271 store: new Roo.data.SimpleStore({
46274 data : this.formats // from states.js
46278 //autoCreate : {tag: "div", size: "20"},
46279 displayField:'tag',
46283 triggerAction: 'all',
46284 emptyText:'Add tag',
46285 selectOnFocus:true,
46288 'select': function(c, r, i) {
46289 editorcore.insertTag(r.get('tag'));
46295 tb.addField(this.formatCombo);
46299 if(!this.disable.format){
46304 btn('strikethrough')
46307 if(!this.disable.fontSize){
46312 btn('increasefontsize', false, editorcore.adjustFont),
46313 btn('decreasefontsize', false, editorcore.adjustFont)
46318 if(!this.disable.colors){
46321 id:editorcore.frameId +'-forecolor',
46322 cls:'x-btn-icon x-edit-forecolor',
46323 clickEvent:'mousedown',
46324 tooltip: this.buttonTips['forecolor'] || undefined,
46326 menu : new Roo.menu.ColorMenu({
46327 allowReselect: true,
46328 focus: Roo.emptyFn,
46331 selectHandler: function(cp, color){
46332 editorcore.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
46333 editor.deferFocus();
46336 clickEvent:'mousedown'
46339 id:editorcore.frameId +'backcolor',
46340 cls:'x-btn-icon x-edit-backcolor',
46341 clickEvent:'mousedown',
46342 tooltip: this.buttonTips['backcolor'] || undefined,
46344 menu : new Roo.menu.ColorMenu({
46345 focus: Roo.emptyFn,
46348 allowReselect: true,
46349 selectHandler: function(cp, color){
46351 editorcore.execCmd('useCSS', false);
46352 editorcore.execCmd('hilitecolor', color);
46353 editorcore.execCmd('useCSS', true);
46354 editor.deferFocus();
46356 editorcore.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
46357 Roo.isSafari || Roo.isIE ? '#'+color : color);
46358 editor.deferFocus();
46362 clickEvent:'mousedown'
46367 // now add all the items...
46370 if(!this.disable.alignments){
46373 btn('justifyleft'),
46374 btn('justifycenter'),
46375 btn('justifyright')
46379 //if(!Roo.isSafari){
46380 if(!this.disable.links){
46383 btn('createlink', false, this.createLink) /// MOVE TO HERE?!!?!?!?!
46387 if(!this.disable.lists){
46390 btn('insertorderedlist'),
46391 btn('insertunorderedlist')
46394 if(!this.disable.sourceEdit){
46397 btn('sourceedit', true, function(btn){
46398 this.toggleSourceEdit(btn.pressed);
46405 // special menu.. - needs to be tidied up..
46406 if (!this.disable.special) {
46409 cls: 'x-edit-none',
46415 for (var i =0; i < this.specialChars.length; i++) {
46416 smenu.menu.items.push({
46418 html: this.specialChars[i],
46419 handler: function(a,b) {
46420 editorcore.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
46421 //editor.insertAtCursor(a.html);
46435 if (!this.disable.cleanStyles) {
46437 cls: 'x-btn-icon x-btn-clear',
46443 for (var i =0; i < this.cleanStyles.length; i++) {
46444 cmenu.menu.items.push({
46445 actiontype : this.cleanStyles[i],
46446 html: 'Remove ' + this.cleanStyles[i],
46447 handler: function(a,b) {
46450 var c = Roo.get(editorcore.doc.body);
46451 c.select('[style]').each(function(s) {
46452 s.dom.style.removeProperty(a.actiontype);
46454 editorcore.syncValue();
46459 cmenu.menu.items.push({
46460 actiontype : 'tablewidths',
46461 html: 'Remove Table Widths',
46462 handler: function(a,b) {
46463 editorcore.cleanTableWidths();
46464 editorcore.syncValue();
46468 cmenu.menu.items.push({
46469 actiontype : 'word',
46470 html: 'Remove MS Word Formating',
46471 handler: function(a,b) {
46472 editorcore.cleanWord();
46473 editorcore.syncValue();
46478 cmenu.menu.items.push({
46479 actiontype : 'all',
46480 html: 'Remove All Styles',
46481 handler: function(a,b) {
46483 var c = Roo.get(editorcore.doc.body);
46484 c.select('[style]').each(function(s) {
46485 s.dom.removeAttribute('style');
46487 editorcore.syncValue();
46492 cmenu.menu.items.push({
46493 actiontype : 'all',
46494 html: 'Remove All CSS Classes',
46495 handler: function(a,b) {
46497 var c = Roo.get(editorcore.doc.body);
46498 c.select('[class]').each(function(s) {
46499 s.dom.removeAttribute('class');
46501 editorcore.cleanWord();
46502 editorcore.syncValue();
46507 cmenu.menu.items.push({
46508 actiontype : 'tidy',
46509 html: 'Tidy HTML Source',
46510 handler: function(a,b) {
46511 editorcore.doc.body.innerHTML = editorcore.domToHTML();
46512 editorcore.syncValue();
46521 if (!this.disable.specialElements) {
46524 cls: 'x-edit-none',
46529 for (var i =0; i < this.specialElements.length; i++) {
46530 semenu.menu.items.push(
46532 handler: function(a,b) {
46533 editor.insertAtCursor(this.ihtml);
46535 }, this.specialElements[i])
46547 for(var i =0; i< this.btns.length;i++) {
46548 var b = Roo.factory(this.btns[i],Roo.form);
46549 b.cls = 'x-edit-none';
46551 if(typeof(this.btns[i].cls) != 'undefined' && this.btns[i].cls.indexOf('x-init-enable') !== -1){
46552 b.cls += ' x-init-enable';
46555 b.scope = editorcore;
46563 // disable everything...
46565 this.tb.items.each(function(item){
46568 item.id != editorcore.frameId+ '-sourceedit' &&
46569 (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)
46575 this.rendered = true;
46577 // the all the btns;
46578 editor.on('editorevent', this.updateToolbar, this);
46579 // other toolbars need to implement this..
46580 //editor.on('editmodechange', this.updateToolbar, this);
46584 relayBtnCmd : function(btn) {
46585 this.editorcore.relayCmd(btn.cmd);
46587 // private used internally
46588 createLink : function(){
46589 Roo.log("create link?");
46590 var url = prompt(this.createLinkText, this.defaultLinkValue);
46591 if(url && url != 'http:/'+'/'){
46592 this.editorcore.relayCmd('createlink', url);
46598 * Protected method that will not generally be called directly. It triggers
46599 * a toolbar update by reading the markup state of the current selection in the editor.
46601 updateToolbar: function(){
46603 if(!this.editorcore.activated){
46604 this.editor.onFirstFocus();
46608 var btns = this.tb.items.map,
46609 doc = this.editorcore.doc,
46610 frameId = this.editorcore.frameId;
46612 if(!this.disable.font && !Roo.isSafari){
46614 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
46615 if(name != this.fontSelect.dom.value){
46616 this.fontSelect.dom.value = name;
46620 if(!this.disable.format){
46621 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
46622 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
46623 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
46624 btns[frameId + '-strikethrough'].toggle(doc.queryCommandState('strikethrough'));
46626 if(!this.disable.alignments){
46627 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
46628 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
46629 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
46631 if(!Roo.isSafari && !this.disable.lists){
46632 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
46633 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
46636 var ans = this.editorcore.getAllAncestors();
46637 if (this.formatCombo) {
46640 var store = this.formatCombo.store;
46641 this.formatCombo.setValue("");
46642 for (var i =0; i < ans.length;i++) {
46643 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
46645 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
46653 // hides menus... - so this cant be on a menu...
46654 Roo.menu.MenuMgr.hideAll();
46656 //this.editorsyncValue();
46660 createFontOptions : function(){
46661 var buf = [], fs = this.fontFamilies, ff, lc;
46665 for(var i = 0, len = fs.length; i< len; i++){
46667 lc = ff.toLowerCase();
46669 '<option value="',lc,'" style="font-family:',ff,';"',
46670 (this.defaultFont == lc ? ' selected="true">' : '>'),
46675 return buf.join('');
46678 toggleSourceEdit : function(sourceEditMode){
46680 Roo.log("toolbar toogle");
46681 if(sourceEditMode === undefined){
46682 sourceEditMode = !this.sourceEditMode;
46684 this.sourceEditMode = sourceEditMode === true;
46685 var btn = this.tb.items.get(this.editorcore.frameId +'-sourceedit');
46686 // just toggle the button?
46687 if(btn.pressed !== this.sourceEditMode){
46688 btn.toggle(this.sourceEditMode);
46692 if(sourceEditMode){
46693 Roo.log("disabling buttons");
46694 this.tb.items.each(function(item){
46695 if(item.cmd != 'sourceedit' && (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)){
46701 Roo.log("enabling buttons");
46702 if(this.editorcore.initialized){
46703 this.tb.items.each(function(item){
46709 Roo.log("calling toggole on editor");
46710 // tell the editor that it's been pressed..
46711 this.editor.toggleSourceEdit(sourceEditMode);
46715 * Object collection of toolbar tooltips for the buttons in the editor. The key
46716 * is the command id associated with that button and the value is a valid QuickTips object.
46721 title: 'Bold (Ctrl+B)',
46722 text: 'Make the selected text bold.',
46723 cls: 'x-html-editor-tip'
46726 title: 'Italic (Ctrl+I)',
46727 text: 'Make the selected text italic.',
46728 cls: 'x-html-editor-tip'
46736 title: 'Bold (Ctrl+B)',
46737 text: 'Make the selected text bold.',
46738 cls: 'x-html-editor-tip'
46741 title: 'Italic (Ctrl+I)',
46742 text: 'Make the selected text italic.',
46743 cls: 'x-html-editor-tip'
46746 title: 'Underline (Ctrl+U)',
46747 text: 'Underline the selected text.',
46748 cls: 'x-html-editor-tip'
46751 title: 'Strikethrough',
46752 text: 'Strikethrough the selected text.',
46753 cls: 'x-html-editor-tip'
46755 increasefontsize : {
46756 title: 'Grow Text',
46757 text: 'Increase the font size.',
46758 cls: 'x-html-editor-tip'
46760 decreasefontsize : {
46761 title: 'Shrink Text',
46762 text: 'Decrease the font size.',
46763 cls: 'x-html-editor-tip'
46766 title: 'Text Highlight Color',
46767 text: 'Change the background color of the selected text.',
46768 cls: 'x-html-editor-tip'
46771 title: 'Font Color',
46772 text: 'Change the color of the selected text.',
46773 cls: 'x-html-editor-tip'
46776 title: 'Align Text Left',
46777 text: 'Align text to the left.',
46778 cls: 'x-html-editor-tip'
46781 title: 'Center Text',
46782 text: 'Center text in the editor.',
46783 cls: 'x-html-editor-tip'
46786 title: 'Align Text Right',
46787 text: 'Align text to the right.',
46788 cls: 'x-html-editor-tip'
46790 insertunorderedlist : {
46791 title: 'Bullet List',
46792 text: 'Start a bulleted list.',
46793 cls: 'x-html-editor-tip'
46795 insertorderedlist : {
46796 title: 'Numbered List',
46797 text: 'Start a numbered list.',
46798 cls: 'x-html-editor-tip'
46801 title: 'Hyperlink',
46802 text: 'Make the selected text a hyperlink.',
46803 cls: 'x-html-editor-tip'
46806 title: 'Source Edit',
46807 text: 'Switch to source editing mode.',
46808 cls: 'x-html-editor-tip'
46812 onDestroy : function(){
46815 this.tb.items.each(function(item){
46817 item.menu.removeAll();
46819 item.menu.el.destroy();
46827 onFirstFocus: function() {
46828 this.tb.items.each(function(item){
46837 // <script type="text/javascript">
46840 * Ext JS Library 1.1.1
46841 * Copyright(c) 2006-2007, Ext JS, LLC.
46848 * @class Roo.form.HtmlEditor.ToolbarContext
46853 new Roo.form.HtmlEditor({
46856 { xtype: 'ToolbarStandard', styles : {} }
46857 { xtype: 'ToolbarContext', disable : {} }
46863 * @config : {Object} disable List of elements to disable.. (not done yet.)
46864 * @config : {Object} styles Map of styles available.
46868 Roo.form.HtmlEditor.ToolbarContext = function(config)
46871 Roo.apply(this, config);
46872 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
46873 // dont call parent... till later.
46874 this.styles = this.styles || {};
46879 Roo.form.HtmlEditor.ToolbarContext.types = {
46891 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
46957 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
46962 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
46972 style : 'fontFamily',
46973 displayField: 'display',
46974 optname : 'font-family',
47023 // should we really allow this??
47024 // should this just be
47035 style : 'fontFamily',
47036 displayField: 'display',
47037 optname : 'font-family',
47044 style : 'fontFamily',
47045 displayField: 'display',
47046 optname : 'font-family',
47053 style : 'fontFamily',
47054 displayField: 'display',
47055 optname : 'font-family',
47066 // this should be configurable.. - you can either set it up using stores, or modify options somehwere..
47067 Roo.form.HtmlEditor.ToolbarContext.stores = false;
47069 Roo.form.HtmlEditor.ToolbarContext.options = {
47071 [ 'Helvetica,Arial,sans-serif', 'Helvetica'],
47072 [ 'Courier New', 'Courier New'],
47073 [ 'Tahoma', 'Tahoma'],
47074 [ 'Times New Roman,serif', 'Times'],
47075 [ 'Verdana','Verdana' ]
47079 // fixme - these need to be configurable..
47082 //Roo.form.HtmlEditor.ToolbarContext.types
47085 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
47092 editorcore : false,
47094 * @cfg {Object} disable List of toolbar elements to disable
47099 * @cfg {Object} styles List of styles
47100 * eg. { '*' : [ 'headline' ] , 'TD' : [ 'underline', 'double-underline' ] }
47102 * These must be defined in the page, so they get rendered correctly..
47113 init : function(editor)
47115 this.editor = editor;
47116 this.editorcore = editor.editorcore ? editor.editorcore : editor;
47117 var editorcore = this.editorcore;
47119 var fid = editorcore.frameId;
47121 function btn(id, toggle, handler){
47122 var xid = fid + '-'+ id ;
47126 cls : 'x-btn-icon x-edit-'+id,
47127 enableToggle:toggle !== false,
47128 scope: editorcore, // was editor...
47129 handler:handler||editorcore.relayBtnCmd,
47130 clickEvent:'mousedown',
47131 tooltip: etb.buttonTips[id] || undefined, ///tips ???
47135 // create a new element.
47136 var wdiv = editor.wrap.createChild({
47138 }, editor.wrap.dom.firstChild.nextSibling, true);
47140 // can we do this more than once??
47142 // stop form submits
47145 // disable everything...
47146 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
47147 this.toolbars = {};
47149 for (var i in ty) {
47151 this.toolbars[i] = this.buildToolbar(ty[i],i);
47153 this.tb = this.toolbars.BODY;
47155 this.buildFooter();
47156 this.footer.show();
47157 editor.on('hide', function( ) { this.footer.hide() }, this);
47158 editor.on('show', function( ) { this.footer.show() }, this);
47161 this.rendered = true;
47163 // the all the btns;
47164 editor.on('editorevent', this.updateToolbar, this);
47165 // other toolbars need to implement this..
47166 //editor.on('editmodechange', this.updateToolbar, this);
47172 * Protected method that will not generally be called directly. It triggers
47173 * a toolbar update by reading the markup state of the current selection in the editor.
47175 * Note you can force an update by calling on('editorevent', scope, false)
47177 updateToolbar: function(editor,ev,sel){
47180 // capture mouse up - this is handy for selecting images..
47181 // perhaps should go somewhere else...
47182 if(!this.editorcore.activated){
47183 this.editor.onFirstFocus();
47189 // http://developer.yahoo.com/yui/docs/simple-editor.js.html
47190 // selectNode - might want to handle IE?
47192 (ev.type == 'mouseup' || ev.type == 'click' ) &&
47193 ev.target && ev.target.tagName == 'IMG') {
47194 // they have click on an image...
47195 // let's see if we can change the selection...
47198 var nodeRange = sel.ownerDocument.createRange();
47200 nodeRange.selectNode(sel);
47202 nodeRange.selectNodeContents(sel);
47204 //nodeRange.collapse(true);
47205 var s = this.editorcore.win.getSelection();
47206 s.removeAllRanges();
47207 s.addRange(nodeRange);
47211 var updateFooter = sel ? false : true;
47214 var ans = this.editorcore.getAllAncestors();
47217 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
47220 sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editorcore.doc.body;
47221 sel = sel ? sel : this.editorcore.doc.body;
47222 sel = sel.tagName.length ? sel : this.editorcore.doc.body;
47225 // pick a menu that exists..
47226 var tn = sel.tagName.toUpperCase();
47227 //sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
47229 tn = sel.tagName.toUpperCase();
47231 var lastSel = this.tb.selectedNode;
47233 this.tb.selectedNode = sel;
47235 // if current menu does not match..
47237 if ((this.tb.name != tn) || (lastSel != this.tb.selectedNode) || ev === false) {
47240 ///console.log("show: " + tn);
47241 this.tb = typeof(ty[tn]) != 'undefined' ? this.toolbars[tn] : this.toolbars['*'];
47244 this.tb.items.first().el.innerHTML = tn + ': ';
47247 // update attributes
47248 if (this.tb.fields) {
47249 this.tb.fields.each(function(e) {
47251 e.setValue(sel.style[e.stylename]);
47254 e.setValue(sel.getAttribute(e.attrname));
47258 var hasStyles = false;
47259 for(var i in this.styles) {
47266 var st = this.tb.fields.item(0);
47268 st.store.removeAll();
47271 var cn = sel.className.split(/\s+/);
47274 if (this.styles['*']) {
47276 Roo.each(this.styles['*'], function(v) {
47277 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
47280 if (this.styles[tn]) {
47281 Roo.each(this.styles[tn], function(v) {
47282 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
47286 st.store.loadData(avs);
47290 // flag our selected Node.
47291 this.tb.selectedNode = sel;
47294 Roo.menu.MenuMgr.hideAll();
47298 if (!updateFooter) {
47299 //this.footDisp.dom.innerHTML = '';
47302 // update the footer
47306 this.footerEls = ans.reverse();
47307 Roo.each(this.footerEls, function(a,i) {
47308 if (!a) { return; }
47309 html += html.length ? ' > ' : '';
47311 html += '<span class="x-ed-loc-' + i + '">' + a.tagName + '</span>';
47316 var sz = this.footDisp.up('td').getSize();
47317 this.footDisp.dom.style.width = (sz.width -10) + 'px';
47318 this.footDisp.dom.style.marginLeft = '5px';
47320 this.footDisp.dom.style.overflow = 'hidden';
47322 this.footDisp.dom.innerHTML = html;
47324 //this.editorsyncValue();
47331 onDestroy : function(){
47334 this.tb.items.each(function(item){
47336 item.menu.removeAll();
47338 item.menu.el.destroy();
47346 onFirstFocus: function() {
47347 // need to do this for all the toolbars..
47348 this.tb.items.each(function(item){
47352 buildToolbar: function(tlist, nm)
47354 var editor = this.editor;
47355 var editorcore = this.editorcore;
47356 // create a new element.
47357 var wdiv = editor.wrap.createChild({
47359 }, editor.wrap.dom.firstChild.nextSibling, true);
47362 var tb = new Roo.Toolbar(wdiv);
47365 tb.add(nm+ ": ");
47368 for(var i in this.styles) {
47373 if (styles && styles.length) {
47375 // this needs a multi-select checkbox...
47376 tb.addField( new Roo.form.ComboBox({
47377 store: new Roo.data.SimpleStore({
47379 fields: ['val', 'selected'],
47382 name : '-roo-edit-className',
47383 attrname : 'className',
47384 displayField: 'val',
47388 triggerAction: 'all',
47389 emptyText:'Select Style',
47390 selectOnFocus:true,
47393 'select': function(c, r, i) {
47394 // initial support only for on class per el..
47395 tb.selectedNode.className = r ? r.get('val') : '';
47396 editorcore.syncValue();
47403 var tbc = Roo.form.HtmlEditor.ToolbarContext;
47404 var tbops = tbc.options;
47406 for (var i in tlist) {
47408 var item = tlist[i];
47409 tb.add(item.title + ": ");
47412 //optname == used so you can configure the options available..
47413 var opts = item.opts ? item.opts : false;
47414 if (item.optname) {
47415 opts = tbops[item.optname];
47420 // opts == pulldown..
47421 tb.addField( new Roo.form.ComboBox({
47422 store: typeof(tbc.stores[i]) != 'undefined' ? Roo.factory(tbc.stores[i],Roo.data) : new Roo.data.SimpleStore({
47424 fields: ['val', 'display'],
47427 name : '-roo-edit-' + i,
47429 stylename : item.style ? item.style : false,
47430 displayField: item.displayField ? item.displayField : 'val',
47431 valueField : 'val',
47433 mode: typeof(tbc.stores[i]) != 'undefined' ? 'remote' : 'local',
47435 triggerAction: 'all',
47436 emptyText:'Select',
47437 selectOnFocus:true,
47438 width: item.width ? item.width : 130,
47440 'select': function(c, r, i) {
47442 tb.selectedNode.style[c.stylename] = r.get('val');
47445 tb.selectedNode.setAttribute(c.attrname, r.get('val'));
47454 tb.addField( new Roo.form.TextField({
47457 //allowBlank:false,
47462 tb.addField( new Roo.form.TextField({
47463 name: '-roo-edit-' + i,
47470 'change' : function(f, nv, ov) {
47471 tb.selectedNode.setAttribute(f.attrname, nv);
47472 editorcore.syncValue();
47485 text: 'Stylesheets',
47488 click : function ()
47490 _this.editor.fireEvent('stylesheetsclick', _this.editor);
47498 text: 'Remove Tag',
47501 click : function ()
47504 // undo does not work.
47506 var sn = tb.selectedNode;
47508 var pn = sn.parentNode;
47510 var stn = sn.childNodes[0];
47511 var en = sn.childNodes[sn.childNodes.length - 1 ];
47512 while (sn.childNodes.length) {
47513 var node = sn.childNodes[0];
47514 sn.removeChild(node);
47516 pn.insertBefore(node, sn);
47519 pn.removeChild(sn);
47520 var range = editorcore.createRange();
47522 range.setStart(stn,0);
47523 range.setEnd(en,0); //????
47524 //range.selectNode(sel);
47527 var selection = editorcore.getSelection();
47528 selection.removeAllRanges();
47529 selection.addRange(range);
47533 //_this.updateToolbar(null, null, pn);
47534 _this.updateToolbar(null, null, null);
47535 _this.footDisp.dom.innerHTML = '';
47545 tb.el.on('click', function(e){
47546 e.preventDefault(); // what does this do?
47548 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
47551 // dont need to disable them... as they will get hidden
47556 buildFooter : function()
47559 var fel = this.editor.wrap.createChild();
47560 this.footer = new Roo.Toolbar(fel);
47561 // toolbar has scrolly on left / right?
47562 var footDisp= new Roo.Toolbar.Fill();
47568 handler : function() {
47569 _t.footDisp.scrollTo('left',0,true)
47573 this.footer.add( footDisp );
47578 handler : function() {
47580 _t.footDisp.select('span').last().scrollIntoView(_t.footDisp,true);
47584 var fel = Roo.get(footDisp.el);
47585 fel.addClass('x-editor-context');
47586 this.footDispWrap = fel;
47587 this.footDispWrap.overflow = 'hidden';
47589 this.footDisp = fel.createChild();
47590 this.footDispWrap.on('click', this.onContextClick, this)
47594 onContextClick : function (ev,dom)
47596 ev.preventDefault();
47597 var cn = dom.className;
47599 if (!cn.match(/x-ed-loc-/)) {
47602 var n = cn.split('-').pop();
47603 var ans = this.footerEls;
47607 var range = this.editorcore.createRange();
47609 range.selectNodeContents(sel);
47610 //range.selectNode(sel);
47613 var selection = this.editorcore.getSelection();
47614 selection.removeAllRanges();
47615 selection.addRange(range);
47619 this.updateToolbar(null, null, sel);
47636 * Ext JS Library 1.1.1
47637 * Copyright(c) 2006-2007, Ext JS, LLC.
47639 * Originally Released Under LGPL - original licence link has changed is not relivant.
47642 * <script type="text/javascript">
47646 * @class Roo.form.BasicForm
47647 * @extends Roo.util.Observable
47648 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
47650 * @param {String/HTMLElement/Roo.Element} el The form element or its id
47651 * @param {Object} config Configuration options
47653 Roo.form.BasicForm = function(el, config){
47654 this.allItems = [];
47655 this.childForms = [];
47656 Roo.apply(this, config);
47658 * The Roo.form.Field items in this form.
47659 * @type MixedCollection
47663 this.items = new Roo.util.MixedCollection(false, function(o){
47664 return o.id || (o.id = Roo.id());
47668 * @event beforeaction
47669 * Fires before any action is performed. Return false to cancel the action.
47670 * @param {Form} this
47671 * @param {Action} action The action to be performed
47673 beforeaction: true,
47675 * @event actionfailed
47676 * Fires when an action fails.
47677 * @param {Form} this
47678 * @param {Action} action The action that failed
47680 actionfailed : true,
47682 * @event actioncomplete
47683 * Fires when an action is completed.
47684 * @param {Form} this
47685 * @param {Action} action The action that completed
47687 actioncomplete : true
47692 Roo.form.BasicForm.superclass.constructor.call(this);
47694 Roo.form.BasicForm.popover.apply();
47697 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
47699 * @cfg {String} method
47700 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
47703 * @cfg {DataReader} reader
47704 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
47705 * This is optional as there is built-in support for processing JSON.
47708 * @cfg {DataReader} errorReader
47709 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
47710 * This is completely optional as there is built-in support for processing JSON.
47713 * @cfg {String} url
47714 * The URL to use for form actions if one isn't supplied in the action options.
47717 * @cfg {Boolean} fileUpload
47718 * Set to true if this form is a file upload.
47722 * @cfg {Object} baseParams
47723 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
47728 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
47733 activeAction : null,
47736 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
47737 * or setValues() data instead of when the form was first created.
47739 trackResetOnLoad : false,
47743 * childForms - used for multi-tab forms
47746 childForms : false,
47749 * allItems - full list of fields.
47755 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
47756 * element by passing it or its id or mask the form itself by passing in true.
47759 waitMsgTarget : false,
47764 disableMask : false,
47767 * @cfg {Boolean} errorMask (true|false) default false
47772 * @cfg {Number} maskOffset Default 100
47777 initEl : function(el){
47778 this.el = Roo.get(el);
47779 this.id = this.el.id || Roo.id();
47780 this.el.on('submit', this.onSubmit, this);
47781 this.el.addClass('x-form');
47785 onSubmit : function(e){
47790 * Returns true if client-side validation on the form is successful.
47793 isValid : function(){
47795 var target = false;
47796 this.items.each(function(f){
47803 if(!target && f.el.isVisible(true)){
47808 if(this.errorMask && !valid){
47809 Roo.form.BasicForm.popover.mask(this, target);
47815 * Returns array of invalid form fields.
47819 invalidFields : function()
47822 this.items.each(function(f){
47835 * DEPRICATED Returns true if any fields in this form have changed since their original load.
47838 isDirty : function(){
47840 this.items.each(function(f){
47850 * Returns true if any fields in this form have changed since their original load. (New version)
47854 hasChanged : function()
47857 this.items.each(function(f){
47858 if(f.hasChanged()){
47867 * Resets all hasChanged to 'false' -
47868 * The old 'isDirty' used 'original value..' however this breaks reset() and a few other things.
47869 * So hasChanged storage is only to be used for this purpose
47872 resetHasChanged : function()
47874 this.items.each(function(f){
47875 f.resetHasChanged();
47882 * Performs a predefined action (submit or load) or custom actions you define on this form.
47883 * @param {String} actionName The name of the action type
47884 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
47885 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
47886 * accept other config options):
47888 Property Type Description
47889 ---------------- --------------- ----------------------------------------------------------------------------------
47890 url String The url for the action (defaults to the form's url)
47891 method String The form method to use (defaults to the form's method, or POST if not defined)
47892 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
47893 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
47894 validate the form on the client (defaults to false)
47896 * @return {BasicForm} this
47898 doAction : function(action, options){
47899 if(typeof action == 'string'){
47900 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
47902 if(this.fireEvent('beforeaction', this, action) !== false){
47903 this.beforeAction(action);
47904 action.run.defer(100, action);
47910 * Shortcut to do a submit action.
47911 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
47912 * @return {BasicForm} this
47914 submit : function(options){
47915 this.doAction('submit', options);
47920 * Shortcut to do a load action.
47921 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
47922 * @return {BasicForm} this
47924 load : function(options){
47925 this.doAction('load', options);
47930 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
47931 * @param {Record} record The record to edit
47932 * @return {BasicForm} this
47934 updateRecord : function(record){
47935 record.beginEdit();
47936 var fs = record.fields;
47937 fs.each(function(f){
47938 var field = this.findField(f.name);
47940 record.set(f.name, field.getValue());
47948 * Loads an Roo.data.Record into this form.
47949 * @param {Record} record The record to load
47950 * @return {BasicForm} this
47952 loadRecord : function(record){
47953 this.setValues(record.data);
47958 beforeAction : function(action){
47959 var o = action.options;
47961 if(!this.disableMask) {
47962 if(this.waitMsgTarget === true){
47963 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
47964 }else if(this.waitMsgTarget){
47965 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
47966 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
47968 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
47976 afterAction : function(action, success){
47977 this.activeAction = null;
47978 var o = action.options;
47980 if(!this.disableMask) {
47981 if(this.waitMsgTarget === true){
47983 }else if(this.waitMsgTarget){
47984 this.waitMsgTarget.unmask();
47986 Roo.MessageBox.updateProgress(1);
47987 Roo.MessageBox.hide();
47995 Roo.callback(o.success, o.scope, [this, action]);
47996 this.fireEvent('actioncomplete', this, action);
48000 // failure condition..
48001 // we have a scenario where updates need confirming.
48002 // eg. if a locking scenario exists..
48003 // we look for { errors : { needs_confirm : true }} in the response.
48005 (typeof(action.result) != 'undefined') &&
48006 (typeof(action.result.errors) != 'undefined') &&
48007 (typeof(action.result.errors.needs_confirm) != 'undefined')
48010 Roo.MessageBox.confirm(
48011 "Change requires confirmation",
48012 action.result.errorMsg,
48017 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
48027 Roo.callback(o.failure, o.scope, [this, action]);
48028 // show an error message if no failed handler is set..
48029 if (!this.hasListener('actionfailed')) {
48030 Roo.MessageBox.alert("Error",
48031 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
48032 action.result.errorMsg :
48033 "Saving Failed, please check your entries or try again"
48037 this.fireEvent('actionfailed', this, action);
48043 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
48044 * @param {String} id The value to search for
48047 findField : function(id){
48048 var field = this.items.get(id);
48050 this.items.each(function(f){
48051 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
48057 return field || null;
48061 * Add a secondary form to this one,
48062 * Used to provide tabbed forms. One form is primary, with hidden values
48063 * which mirror the elements from the other forms.
48065 * @param {Roo.form.Form} form to add.
48068 addForm : function(form)
48071 if (this.childForms.indexOf(form) > -1) {
48075 this.childForms.push(form);
48077 Roo.each(form.allItems, function (fe) {
48079 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
48080 if (this.findField(n)) { // already added..
48083 var add = new Roo.form.Hidden({
48086 add.render(this.el);
48093 * Mark fields in this form invalid in bulk.
48094 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
48095 * @return {BasicForm} this
48097 markInvalid : function(errors){
48098 if(errors instanceof Array){
48099 for(var i = 0, len = errors.length; i < len; i++){
48100 var fieldError = errors[i];
48101 var f = this.findField(fieldError.id);
48103 f.markInvalid(fieldError.msg);
48109 if(typeof errors[id] != 'function' && (field = this.findField(id))){
48110 field.markInvalid(errors[id]);
48114 Roo.each(this.childForms || [], function (f) {
48115 f.markInvalid(errors);
48122 * Set values for fields in this form in bulk.
48123 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
48124 * @return {BasicForm} this
48126 setValues : function(values){
48127 if(values instanceof Array){ // array of objects
48128 for(var i = 0, len = values.length; i < len; i++){
48130 var f = this.findField(v.id);
48132 f.setValue(v.value);
48133 if(this.trackResetOnLoad){
48134 f.originalValue = f.getValue();
48138 }else{ // object hash
48141 if(typeof values[id] != 'function' && (field = this.findField(id))){
48143 if (field.setFromData &&
48144 field.valueField &&
48145 field.displayField &&
48146 // combos' with local stores can
48147 // be queried via setValue()
48148 // to set their value..
48149 (field.store && !field.store.isLocal)
48153 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
48154 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
48155 field.setFromData(sd);
48158 field.setValue(values[id]);
48162 if(this.trackResetOnLoad){
48163 field.originalValue = field.getValue();
48168 this.resetHasChanged();
48171 Roo.each(this.childForms || [], function (f) {
48172 f.setValues(values);
48173 f.resetHasChanged();
48180 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
48181 * they are returned as an array.
48182 * @param {Boolean} asString
48185 getValues : function(asString){
48186 if (this.childForms) {
48187 // copy values from the child forms
48188 Roo.each(this.childForms, function (f) {
48189 this.setValues(f.getValues());
48194 if (typeof(FormData) != 'undefined' && asString !== true) {
48195 // this relies on a 'recent' version of chrome apparently...
48197 var fd = (new FormData(this.el.dom)).entries();
48199 var ent = fd.next();
48200 while (!ent.done) {
48201 ret[ent.value[0]] = ent.value[1]; // not sure how this will handle duplicates..
48212 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
48213 if(asString === true){
48216 return Roo.urlDecode(fs);
48220 * Returns the fields in this form as an object with key/value pairs.
48221 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
48224 getFieldValues : function(with_hidden)
48226 if (this.childForms) {
48227 // copy values from the child forms
48228 // should this call getFieldValues - probably not as we do not currently copy
48229 // hidden fields when we generate..
48230 Roo.each(this.childForms, function (f) {
48231 this.setValues(f.getValues());
48236 this.items.each(function(f){
48237 if (!f.getName()) {
48240 var v = f.getValue();
48241 if (f.inputType =='radio') {
48242 if (typeof(ret[f.getName()]) == 'undefined') {
48243 ret[f.getName()] = ''; // empty..
48246 if (!f.el.dom.checked) {
48250 v = f.el.dom.value;
48254 // not sure if this supported any more..
48255 if ((typeof(v) == 'object') && f.getRawValue) {
48256 v = f.getRawValue() ; // dates..
48258 // combo boxes where name != hiddenName...
48259 if (f.name != f.getName()) {
48260 ret[f.name] = f.getRawValue();
48262 ret[f.getName()] = v;
48269 * Clears all invalid messages in this form.
48270 * @return {BasicForm} this
48272 clearInvalid : function(){
48273 this.items.each(function(f){
48277 Roo.each(this.childForms || [], function (f) {
48286 * Resets this form.
48287 * @return {BasicForm} this
48289 reset : function(){
48290 this.items.each(function(f){
48294 Roo.each(this.childForms || [], function (f) {
48297 this.resetHasChanged();
48303 * Add Roo.form components to this form.
48304 * @param {Field} field1
48305 * @param {Field} field2 (optional)
48306 * @param {Field} etc (optional)
48307 * @return {BasicForm} this
48310 this.items.addAll(Array.prototype.slice.call(arguments, 0));
48316 * Removes a field from the items collection (does NOT remove its markup).
48317 * @param {Field} field
48318 * @return {BasicForm} this
48320 remove : function(field){
48321 this.items.remove(field);
48326 * Looks at the fields in this form, checks them for an id attribute,
48327 * and calls applyTo on the existing dom element with that id.
48328 * @return {BasicForm} this
48330 render : function(){
48331 this.items.each(function(f){
48332 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
48340 * Calls {@link Ext#apply} for all fields in this form with the passed object.
48341 * @param {Object} values
48342 * @return {BasicForm} this
48344 applyToFields : function(o){
48345 this.items.each(function(f){
48352 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
48353 * @param {Object} values
48354 * @return {BasicForm} this
48356 applyIfToFields : function(o){
48357 this.items.each(function(f){
48365 Roo.BasicForm = Roo.form.BasicForm;
48367 Roo.apply(Roo.form.BasicForm, {
48381 intervalID : false,
48387 if(this.isApplied){
48392 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
48393 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
48394 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
48395 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
48398 this.maskEl.top.enableDisplayMode("block");
48399 this.maskEl.left.enableDisplayMode("block");
48400 this.maskEl.bottom.enableDisplayMode("block");
48401 this.maskEl.right.enableDisplayMode("block");
48403 Roo.get(document.body).on('click', function(){
48407 Roo.get(document.body).on('touchstart', function(){
48411 this.isApplied = true
48414 mask : function(form, target)
48418 this.target = target;
48420 if(!this.form.errorMask || !target.el){
48424 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.x-layout-active-content', 100, true) || Roo.get(document.body);
48426 var ot = this.target.el.calcOffsetsTo(scrollable);
48428 var scrollTo = ot[1] - this.form.maskOffset;
48430 scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
48432 scrollable.scrollTo('top', scrollTo);
48434 var el = this.target.wrap || this.target.el;
48436 var box = el.getBox();
48438 this.maskEl.top.setStyle('position', 'absolute');
48439 this.maskEl.top.setStyle('z-index', 10000);
48440 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
48441 this.maskEl.top.setLeft(0);
48442 this.maskEl.top.setTop(0);
48443 this.maskEl.top.show();
48445 this.maskEl.left.setStyle('position', 'absolute');
48446 this.maskEl.left.setStyle('z-index', 10000);
48447 this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
48448 this.maskEl.left.setLeft(0);
48449 this.maskEl.left.setTop(box.y - this.padding);
48450 this.maskEl.left.show();
48452 this.maskEl.bottom.setStyle('position', 'absolute');
48453 this.maskEl.bottom.setStyle('z-index', 10000);
48454 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
48455 this.maskEl.bottom.setLeft(0);
48456 this.maskEl.bottom.setTop(box.bottom + this.padding);
48457 this.maskEl.bottom.show();
48459 this.maskEl.right.setStyle('position', 'absolute');
48460 this.maskEl.right.setStyle('z-index', 10000);
48461 this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
48462 this.maskEl.right.setLeft(box.right + this.padding);
48463 this.maskEl.right.setTop(box.y - this.padding);
48464 this.maskEl.right.show();
48466 this.intervalID = window.setInterval(function() {
48467 Roo.form.BasicForm.popover.unmask();
48470 window.onwheel = function(){ return false;};
48472 (function(){ this.isMasked = true; }).defer(500, this);
48476 unmask : function()
48478 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
48482 this.maskEl.top.setStyle('position', 'absolute');
48483 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
48484 this.maskEl.top.hide();
48486 this.maskEl.left.setStyle('position', 'absolute');
48487 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
48488 this.maskEl.left.hide();
48490 this.maskEl.bottom.setStyle('position', 'absolute');
48491 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
48492 this.maskEl.bottom.hide();
48494 this.maskEl.right.setStyle('position', 'absolute');
48495 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
48496 this.maskEl.right.hide();
48498 window.onwheel = function(){ return true;};
48500 if(this.intervalID){
48501 window.clearInterval(this.intervalID);
48502 this.intervalID = false;
48505 this.isMasked = false;
48513 * Ext JS Library 1.1.1
48514 * Copyright(c) 2006-2007, Ext JS, LLC.
48516 * Originally Released Under LGPL - original licence link has changed is not relivant.
48519 * <script type="text/javascript">
48523 * @class Roo.form.Form
48524 * @extends Roo.form.BasicForm
48525 * @children Roo.form.Column Roo.form.FieldSet Roo.form.Row Roo.form.Field Roo.Button Roo.form.TextItem
48526 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
48528 * @param {Object} config Configuration options
48530 Roo.form.Form = function(config){
48532 if (config.items) {
48533 xitems = config.items;
48534 delete config.items;
48538 Roo.form.Form.superclass.constructor.call(this, null, config);
48539 this.url = this.url || this.action;
48541 this.root = new Roo.form.Layout(Roo.applyIf({
48545 this.active = this.root;
48547 * Array of all the buttons that have been added to this form via {@link addButton}
48551 this.allItems = [];
48554 * @event clientvalidation
48555 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
48556 * @param {Form} this
48557 * @param {Boolean} valid true if the form has passed client-side validation
48559 clientvalidation: true,
48562 * Fires when the form is rendered
48563 * @param {Roo.form.Form} form
48568 if (this.progressUrl) {
48569 // push a hidden field onto the list of fields..
48573 name : 'UPLOAD_IDENTIFIER'
48578 Roo.each(xitems, this.addxtype, this);
48582 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
48584 * @cfg {Roo.Button} buttons[] buttons at bottom of form
48588 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
48591 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
48594 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
48596 buttonAlign:'center',
48599 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
48604 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
48605 * This property cascades to child containers if not set.
48610 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
48611 * fires a looping event with that state. This is required to bind buttons to the valid
48612 * state using the config value formBind:true on the button.
48614 monitorValid : false,
48617 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
48622 * @cfg {String} progressUrl - Url to return progress data
48625 progressUrl : false,
48627 * @cfg {boolean|FormData} formData - true to use new 'FormData' post, or set to a new FormData({dom form}) Object, if
48628 * sending a formdata with extra parameters - eg uploaded elements.
48634 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
48635 * fields are added and the column is closed. If no fields are passed the column remains open
48636 * until end() is called.
48637 * @param {Object} config The config to pass to the column
48638 * @param {Field} field1 (optional)
48639 * @param {Field} field2 (optional)
48640 * @param {Field} etc (optional)
48641 * @return Column The column container object
48643 column : function(c){
48644 var col = new Roo.form.Column(c);
48646 if(arguments.length > 1){ // duplicate code required because of Opera
48647 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
48654 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
48655 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
48656 * until end() is called.
48657 * @param {Object} config The config to pass to the fieldset
48658 * @param {Field} field1 (optional)
48659 * @param {Field} field2 (optional)
48660 * @param {Field} etc (optional)
48661 * @return FieldSet The fieldset container object
48663 fieldset : function(c){
48664 var fs = new Roo.form.FieldSet(c);
48666 if(arguments.length > 1){ // duplicate code required because of Opera
48667 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
48674 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
48675 * fields are added and the container is closed. If no fields are passed the container remains open
48676 * until end() is called.
48677 * @param {Object} config The config to pass to the Layout
48678 * @param {Field} field1 (optional)
48679 * @param {Field} field2 (optional)
48680 * @param {Field} etc (optional)
48681 * @return Layout The container object
48683 container : function(c){
48684 var l = new Roo.form.Layout(c);
48686 if(arguments.length > 1){ // duplicate code required because of Opera
48687 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
48694 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
48695 * @param {Object} container A Roo.form.Layout or subclass of Layout
48696 * @return {Form} this
48698 start : function(c){
48699 // cascade label info
48700 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
48701 this.active.stack.push(c);
48702 c.ownerCt = this.active;
48708 * Closes the current open container
48709 * @return {Form} this
48712 if(this.active == this.root){
48715 this.active = this.active.ownerCt;
48720 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
48721 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
48722 * as the label of the field.
48723 * @param {Field} field1
48724 * @param {Field} field2 (optional)
48725 * @param {Field} etc. (optional)
48726 * @return {Form} this
48729 this.active.stack.push.apply(this.active.stack, arguments);
48730 this.allItems.push.apply(this.allItems,arguments);
48732 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
48733 if(a[i].isFormField){
48738 Roo.form.Form.superclass.add.apply(this, r);
48748 * Find any element that has been added to a form, using it's ID or name
48749 * This can include framesets, columns etc. along with regular fields..
48750 * @param {String} id - id or name to find.
48752 * @return {Element} e - or false if nothing found.
48754 findbyId : function(id)
48760 Roo.each(this.allItems, function(f){
48761 if (f.id == id || f.name == id ){
48772 * Render this form into the passed container. This should only be called once!
48773 * @param {String/HTMLElement/Element} container The element this component should be rendered into
48774 * @return {Form} this
48776 render : function(ct)
48782 var o = this.autoCreate || {
48784 method : this.method || 'POST',
48785 id : this.id || Roo.id()
48787 this.initEl(ct.createChild(o));
48789 this.root.render(this.el);
48793 this.items.each(function(f){
48794 f.render('x-form-el-'+f.id);
48797 if(this.buttons.length > 0){
48798 // tables are required to maintain order and for correct IE layout
48799 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
48800 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
48801 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
48803 var tr = tb.getElementsByTagName('tr')[0];
48804 for(var i = 0, len = this.buttons.length; i < len; i++) {
48805 var b = this.buttons[i];
48806 var td = document.createElement('td');
48807 td.className = 'x-form-btn-td';
48808 b.render(tr.appendChild(td));
48811 if(this.monitorValid){ // initialize after render
48812 this.startMonitoring();
48814 this.fireEvent('rendered', this);
48819 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
48820 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
48821 * object or a valid Roo.DomHelper element config
48822 * @param {Function} handler The function called when the button is clicked
48823 * @param {Object} scope (optional) The scope of the handler function
48824 * @return {Roo.Button}
48826 addButton : function(config, handler, scope){
48830 minWidth: this.minButtonWidth,
48833 if(typeof config == "string"){
48836 Roo.apply(bc, config);
48838 var btn = new Roo.Button(null, bc);
48839 this.buttons.push(btn);
48844 * Adds a series of form elements (using the xtype property as the factory method.
48845 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
48846 * @param {Object} config
48849 addxtype : function()
48851 var ar = Array.prototype.slice.call(arguments, 0);
48853 for(var i = 0; i < ar.length; i++) {
48855 continue; // skip -- if this happends something invalid got sent, we
48856 // should ignore it, as basically that interface element will not show up
48857 // and that should be pretty obvious!!
48860 if (Roo.form[ar[i].xtype]) {
48862 var fe = Roo.factory(ar[i], Roo.form);
48868 fe.store.form = this;
48873 this.allItems.push(fe);
48874 if (fe.items && fe.addxtype) {
48875 fe.addxtype.apply(fe, fe.items);
48885 // console.log('adding ' + ar[i].xtype);
48887 if (ar[i].xtype == 'Button') {
48888 //console.log('adding button');
48889 //console.log(ar[i]);
48890 this.addButton(ar[i]);
48891 this.allItems.push(fe);
48895 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
48896 alert('end is not supported on xtype any more, use items');
48898 // //console.log('adding end');
48906 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
48907 * option "monitorValid"
48909 startMonitoring : function(){
48912 Roo.TaskMgr.start({
48913 run : this.bindHandler,
48914 interval : this.monitorPoll || 200,
48921 * Stops monitoring of the valid state of this form
48923 stopMonitoring : function(){
48924 this.bound = false;
48928 bindHandler : function(){
48930 return false; // stops binding
48933 this.items.each(function(f){
48934 if(!f.isValid(true)){
48939 for(var i = 0, len = this.buttons.length; i < len; i++){
48940 var btn = this.buttons[i];
48941 if(btn.formBind === true && btn.disabled === valid){
48942 btn.setDisabled(!valid);
48945 this.fireEvent('clientvalidation', this, valid);
48959 Roo.Form = Roo.form.Form;
48962 * Ext JS Library 1.1.1
48963 * Copyright(c) 2006-2007, Ext JS, LLC.
48965 * Originally Released Under LGPL - original licence link has changed is not relivant.
48968 * <script type="text/javascript">
48971 // as we use this in bootstrap.
48972 Roo.namespace('Roo.form');
48974 * @class Roo.form.Action
48975 * Internal Class used to handle form actions
48977 * @param {Roo.form.BasicForm} el The form element or its id
48978 * @param {Object} config Configuration options
48983 // define the action interface
48984 Roo.form.Action = function(form, options){
48986 this.options = options || {};
48989 * Client Validation Failed
48992 Roo.form.Action.CLIENT_INVALID = 'client';
48994 * Server Validation Failed
48997 Roo.form.Action.SERVER_INVALID = 'server';
48999 * Connect to Server Failed
49002 Roo.form.Action.CONNECT_FAILURE = 'connect';
49004 * Reading Data from Server Failed
49007 Roo.form.Action.LOAD_FAILURE = 'load';
49009 Roo.form.Action.prototype = {
49011 failureType : undefined,
49012 response : undefined,
49013 result : undefined,
49015 // interface method
49016 run : function(options){
49020 // interface method
49021 success : function(response){
49025 // interface method
49026 handleResponse : function(response){
49030 // default connection failure
49031 failure : function(response){
49033 this.response = response;
49034 this.failureType = Roo.form.Action.CONNECT_FAILURE;
49035 this.form.afterAction(this, false);
49038 processResponse : function(response){
49039 this.response = response;
49040 if(!response.responseText){
49043 this.result = this.handleResponse(response);
49044 return this.result;
49047 // utility functions used internally
49048 getUrl : function(appendParams){
49049 var url = this.options.url || this.form.url || this.form.el.dom.action;
49051 var p = this.getParams();
49053 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
49059 getMethod : function(){
49060 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
49063 getParams : function(){
49064 var bp = this.form.baseParams;
49065 var p = this.options.params;
49067 if(typeof p == "object"){
49068 p = Roo.urlEncode(Roo.applyIf(p, bp));
49069 }else if(typeof p == 'string' && bp){
49070 p += '&' + Roo.urlEncode(bp);
49073 p = Roo.urlEncode(bp);
49078 createCallback : function(){
49080 success: this.success,
49081 failure: this.failure,
49083 timeout: (this.form.timeout*1000),
49084 upload: this.form.fileUpload ? this.success : undefined
49089 Roo.form.Action.Submit = function(form, options){
49090 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
49093 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
49096 haveProgress : false,
49097 uploadComplete : false,
49099 // uploadProgress indicator.
49100 uploadProgress : function()
49102 if (!this.form.progressUrl) {
49106 if (!this.haveProgress) {
49107 Roo.MessageBox.progress("Uploading", "Uploading");
49109 if (this.uploadComplete) {
49110 Roo.MessageBox.hide();
49114 this.haveProgress = true;
49116 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
49118 var c = new Roo.data.Connection();
49120 url : this.form.progressUrl,
49125 success : function(req){
49126 //console.log(data);
49130 rdata = Roo.decode(req.responseText)
49132 Roo.log("Invalid data from server..");
49136 if (!rdata || !rdata.success) {
49138 Roo.MessageBox.alert(Roo.encode(rdata));
49141 var data = rdata.data;
49143 if (this.uploadComplete) {
49144 Roo.MessageBox.hide();
49149 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
49150 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
49153 this.uploadProgress.defer(2000,this);
49156 failure: function(data) {
49157 Roo.log('progress url failed ');
49168 // run get Values on the form, so it syncs any secondary forms.
49169 this.form.getValues();
49171 var o = this.options;
49172 var method = this.getMethod();
49173 var isPost = method == 'POST';
49174 if(o.clientValidation === false || this.form.isValid()){
49176 if (this.form.progressUrl) {
49177 this.form.findField('UPLOAD_IDENTIFIER').setValue(
49178 (new Date() * 1) + '' + Math.random());
49183 Roo.Ajax.request(Roo.apply(this.createCallback(), {
49184 form:this.form.el.dom,
49185 url:this.getUrl(!isPost),
49187 params:isPost ? this.getParams() : null,
49188 isUpload: this.form.fileUpload,
49189 formData : this.form.formData
49192 this.uploadProgress();
49194 }else if (o.clientValidation !== false){ // client validation failed
49195 this.failureType = Roo.form.Action.CLIENT_INVALID;
49196 this.form.afterAction(this, false);
49200 success : function(response)
49202 this.uploadComplete= true;
49203 if (this.haveProgress) {
49204 Roo.MessageBox.hide();
49208 var result = this.processResponse(response);
49209 if(result === true || result.success){
49210 this.form.afterAction(this, true);
49214 this.form.markInvalid(result.errors);
49215 this.failureType = Roo.form.Action.SERVER_INVALID;
49217 this.form.afterAction(this, false);
49219 failure : function(response)
49221 this.uploadComplete= true;
49222 if (this.haveProgress) {
49223 Roo.MessageBox.hide();
49226 this.response = response;
49227 this.failureType = Roo.form.Action.CONNECT_FAILURE;
49228 this.form.afterAction(this, false);
49231 handleResponse : function(response){
49232 if(this.form.errorReader){
49233 var rs = this.form.errorReader.read(response);
49236 for(var i = 0, len = rs.records.length; i < len; i++) {
49237 var r = rs.records[i];
49238 errors[i] = r.data;
49241 if(errors.length < 1){
49245 success : rs.success,
49251 ret = Roo.decode(response.responseText);
49255 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
49265 Roo.form.Action.Load = function(form, options){
49266 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
49267 this.reader = this.form.reader;
49270 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
49275 Roo.Ajax.request(Roo.apply(
49276 this.createCallback(), {
49277 method:this.getMethod(),
49278 url:this.getUrl(false),
49279 params:this.getParams()
49283 success : function(response){
49285 var result = this.processResponse(response);
49286 if(result === true || !result.success || !result.data){
49287 this.failureType = Roo.form.Action.LOAD_FAILURE;
49288 this.form.afterAction(this, false);
49291 this.form.clearInvalid();
49292 this.form.setValues(result.data);
49293 this.form.afterAction(this, true);
49296 handleResponse : function(response){
49297 if(this.form.reader){
49298 var rs = this.form.reader.read(response);
49299 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
49301 success : rs.success,
49305 return Roo.decode(response.responseText);
49309 Roo.form.Action.ACTION_TYPES = {
49310 'load' : Roo.form.Action.Load,
49311 'submit' : Roo.form.Action.Submit
49314 * Ext JS Library 1.1.1
49315 * Copyright(c) 2006-2007, Ext JS, LLC.
49317 * Originally Released Under LGPL - original licence link has changed is not relivant.
49320 * <script type="text/javascript">
49324 * @class Roo.form.Layout
49325 * @extends Roo.Component
49326 * @children Roo.form.Column Roo.form.Row Roo.form.Field Roo.Button Roo.form.TextItem
49327 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
49329 * @param {Object} config Configuration options
49331 Roo.form.Layout = function(config){
49333 if (config.items) {
49334 xitems = config.items;
49335 delete config.items;
49337 Roo.form.Layout.superclass.constructor.call(this, config);
49339 Roo.each(xitems, this.addxtype, this);
49343 Roo.extend(Roo.form.Layout, Roo.Component, {
49345 * @cfg {String/Object} autoCreate
49346 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
49349 * @cfg {String/Object/Function} style
49350 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
49351 * a function which returns such a specification.
49354 * @cfg {String} labelAlign
49355 * Valid values are "left," "top" and "right" (defaults to "left")
49358 * @cfg {Number} labelWidth
49359 * Fixed width in pixels of all field labels (defaults to undefined)
49362 * @cfg {Boolean} clear
49363 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
49367 * @cfg {String} labelSeparator
49368 * The separator to use after field labels (defaults to ':')
49370 labelSeparator : ':',
49372 * @cfg {Boolean} hideLabels
49373 * True to suppress the display of field labels in this layout (defaults to false)
49375 hideLabels : false,
49378 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
49383 onRender : function(ct, position){
49384 if(this.el){ // from markup
49385 this.el = Roo.get(this.el);
49386 }else { // generate
49387 var cfg = this.getAutoCreate();
49388 this.el = ct.createChild(cfg, position);
49391 this.el.applyStyles(this.style);
49393 if(this.labelAlign){
49394 this.el.addClass('x-form-label-'+this.labelAlign);
49396 if(this.hideLabels){
49397 this.labelStyle = "display:none";
49398 this.elementStyle = "padding-left:0;";
49400 if(typeof this.labelWidth == 'number'){
49401 this.labelStyle = "width:"+this.labelWidth+"px;";
49402 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
49404 if(this.labelAlign == 'top'){
49405 this.labelStyle = "width:auto;";
49406 this.elementStyle = "padding-left:0;";
49409 var stack = this.stack;
49410 var slen = stack.length;
49412 if(!this.fieldTpl){
49413 var t = new Roo.Template(
49414 '<div class="x-form-item {5}">',
49415 '<label for="{0}" style="{2}">{1}{4}</label>',
49416 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
49418 '</div><div class="x-form-clear-left"></div>'
49420 t.disableFormats = true;
49422 Roo.form.Layout.prototype.fieldTpl = t;
49424 for(var i = 0; i < slen; i++) {
49425 if(stack[i].isFormField){
49426 this.renderField(stack[i]);
49428 this.renderComponent(stack[i]);
49433 this.el.createChild({cls:'x-form-clear'});
49438 renderField : function(f){
49439 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
49442 f.labelStyle||this.labelStyle||'', //2
49443 this.elementStyle||'', //3
49444 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
49445 f.itemCls||this.itemCls||'' //5
49446 ], true).getPrevSibling());
49450 renderComponent : function(c){
49451 c.render(c.isLayout ? this.el : this.el.createChild());
49454 * Adds a object form elements (using the xtype property as the factory method.)
49455 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
49456 * @param {Object} config
49458 addxtype : function(o)
49460 // create the lement.
49461 o.form = this.form;
49462 var fe = Roo.factory(o, Roo.form);
49463 this.form.allItems.push(fe);
49464 this.stack.push(fe);
49466 if (fe.isFormField) {
49467 this.form.items.add(fe);
49475 * @class Roo.form.Column
49476 * @extends Roo.form.Layout
49477 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
49479 * @param {Object} config Configuration options
49481 Roo.form.Column = function(config){
49482 Roo.form.Column.superclass.constructor.call(this, config);
49485 Roo.extend(Roo.form.Column, Roo.form.Layout, {
49487 * @cfg {Number/String} width
49488 * The fixed width of the column in pixels or CSS value (defaults to "auto")
49491 * @cfg {String/Object} autoCreate
49492 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
49496 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
49499 onRender : function(ct, position){
49500 Roo.form.Column.superclass.onRender.call(this, ct, position);
49502 this.el.setWidth(this.width);
49509 * @class Roo.form.Row
49510 * @extends Roo.form.Layout
49511 * @children Roo.form.Column Roo.form.Row Roo.form.Field Roo.Button Roo.form.TextItem
49512 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
49514 * @param {Object} config Configuration options
49518 Roo.form.Row = function(config){
49519 Roo.form.Row.superclass.constructor.call(this, config);
49522 Roo.extend(Roo.form.Row, Roo.form.Layout, {
49524 * @cfg {Number/String} width
49525 * The fixed width of the column in pixels or CSS value (defaults to "auto")
49528 * @cfg {Number/String} height
49529 * The fixed height of the column in pixels or CSS value (defaults to "auto")
49531 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
49535 onRender : function(ct, position){
49536 //console.log('row render');
49538 var t = new Roo.Template(
49539 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
49540 '<label for="{0}" style="{2}">{1}{4}</label>',
49541 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
49545 t.disableFormats = true;
49547 Roo.form.Layout.prototype.rowTpl = t;
49549 this.fieldTpl = this.rowTpl;
49551 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
49552 var labelWidth = 100;
49554 if ((this.labelAlign != 'top')) {
49555 if (typeof this.labelWidth == 'number') {
49556 labelWidth = this.labelWidth
49558 this.padWidth = 20 + labelWidth;
49562 Roo.form.Column.superclass.onRender.call(this, ct, position);
49564 this.el.setWidth(this.width);
49567 this.el.setHeight(this.height);
49572 renderField : function(f){
49573 f.fieldEl = this.fieldTpl.append(this.el, [
49574 f.id, f.fieldLabel,
49575 f.labelStyle||this.labelStyle||'',
49576 this.elementStyle||'',
49577 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
49578 f.itemCls||this.itemCls||'',
49579 f.width ? f.width + this.padWidth : 160 + this.padWidth
49586 * @class Roo.form.FieldSet
49587 * @extends Roo.form.Layout
49588 * @children Roo.form.Column Roo.form.Row Roo.form.Field Roo.Button Roo.form.TextItem
49589 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
49591 * @param {Object} config Configuration options
49593 Roo.form.FieldSet = function(config){
49594 Roo.form.FieldSet.superclass.constructor.call(this, config);
49597 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
49599 * @cfg {String} legend
49600 * The text to display as the legend for the FieldSet (defaults to '')
49603 * @cfg {String/Object} autoCreate
49604 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
49608 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
49611 onRender : function(ct, position){
49612 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
49614 this.setLegend(this.legend);
49619 setLegend : function(text){
49621 this.el.child('legend').update(text);
49626 * Ext JS Library 1.1.1
49627 * Copyright(c) 2006-2007, Ext JS, LLC.
49629 * Originally Released Under LGPL - original licence link has changed is not relivant.
49632 * <script type="text/javascript">
49635 * @class Roo.form.VTypes
49636 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
49639 Roo.form.VTypes = function(){
49640 // closure these in so they are only created once.
49641 var alpha = /^[a-zA-Z_]+$/;
49642 var alphanum = /^[a-zA-Z0-9_]+$/;
49643 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
49644 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
49646 // All these messages and functions are configurable
49649 * The function used to validate email addresses
49650 * @param {String} value The email address
49652 'email' : function(v){
49653 return email.test(v);
49656 * The error text to display when the email validation function returns false
49659 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
49661 * The keystroke filter mask to be applied on email input
49664 'emailMask' : /[a-z0-9_\.\-@]/i,
49667 * The function used to validate URLs
49668 * @param {String} value The URL
49670 'url' : function(v){
49671 return url.test(v);
49674 * The error text to display when the url validation function returns false
49677 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
49680 * The function used to validate alpha values
49681 * @param {String} value The value
49683 'alpha' : function(v){
49684 return alpha.test(v);
49687 * The error text to display when the alpha validation function returns false
49690 'alphaText' : 'This field should only contain letters and _',
49692 * The keystroke filter mask to be applied on alpha input
49695 'alphaMask' : /[a-z_]/i,
49698 * The function used to validate alphanumeric values
49699 * @param {String} value The value
49701 'alphanum' : function(v){
49702 return alphanum.test(v);
49705 * The error text to display when the alphanumeric validation function returns false
49708 'alphanumText' : 'This field should only contain letters, numbers and _',
49710 * The keystroke filter mask to be applied on alphanumeric input
49713 'alphanumMask' : /[a-z0-9_]/i
49715 }();//<script type="text/javascript">
49718 * @class Roo.form.FCKeditor
49719 * @extends Roo.form.TextArea
49720 * Wrapper around the FCKEditor http://www.fckeditor.net
49722 * Creates a new FCKeditor
49723 * @param {Object} config Configuration options
49725 Roo.form.FCKeditor = function(config){
49726 Roo.form.FCKeditor.superclass.constructor.call(this, config);
49729 * @event editorinit
49730 * Fired when the editor is initialized - you can add extra handlers here..
49731 * @param {FCKeditor} this
49732 * @param {Object} the FCK object.
49739 Roo.form.FCKeditor.editors = { };
49740 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
49742 //defaultAutoCreate : {
49743 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
49747 * @cfg {Object} fck options - see fck manual for details.
49752 * @cfg {Object} fck toolbar set (Basic or Default)
49754 toolbarSet : 'Basic',
49756 * @cfg {Object} fck BasePath
49758 basePath : '/fckeditor/',
49766 onRender : function(ct, position)
49769 this.defaultAutoCreate = {
49771 style:"width:300px;height:60px;",
49772 autocomplete: "new-password"
49775 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
49778 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
49779 if(this.preventScrollbars){
49780 this.el.setStyle("overflow", "hidden");
49782 this.el.setHeight(this.growMin);
49785 //console.log('onrender' + this.getId() );
49786 Roo.form.FCKeditor.editors[this.getId()] = this;
49789 this.replaceTextarea() ;
49793 getEditor : function() {
49794 return this.fckEditor;
49797 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
49798 * @param {Mixed} value The value to set
49802 setValue : function(value)
49804 //console.log('setValue: ' + value);
49806 if(typeof(value) == 'undefined') { // not sure why this is happending...
49809 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
49811 //if(!this.el || !this.getEditor()) {
49812 // this.value = value;
49813 //this.setValue.defer(100,this,[value]);
49817 if(!this.getEditor()) {
49821 this.getEditor().SetData(value);
49828 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
49829 * @return {Mixed} value The field value
49831 getValue : function()
49834 if (this.frame && this.frame.dom.style.display == 'none') {
49835 return Roo.form.FCKeditor.superclass.getValue.call(this);
49838 if(!this.el || !this.getEditor()) {
49840 // this.getValue.defer(100,this);
49845 var value=this.getEditor().GetData();
49846 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
49847 return Roo.form.FCKeditor.superclass.getValue.call(this);
49853 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
49854 * @return {Mixed} value The field value
49856 getRawValue : function()
49858 if (this.frame && this.frame.dom.style.display == 'none') {
49859 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
49862 if(!this.el || !this.getEditor()) {
49863 //this.getRawValue.defer(100,this);
49870 var value=this.getEditor().GetData();
49871 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
49872 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
49876 setSize : function(w,h) {
49880 //if (this.frame && this.frame.dom.style.display == 'none') {
49881 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
49884 //if(!this.el || !this.getEditor()) {
49885 // this.setSize.defer(100,this, [w,h]);
49891 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
49893 this.frame.dom.setAttribute('width', w);
49894 this.frame.dom.setAttribute('height', h);
49895 this.frame.setSize(w,h);
49899 toggleSourceEdit : function(value) {
49903 this.el.dom.style.display = value ? '' : 'none';
49904 this.frame.dom.style.display = value ? 'none' : '';
49909 focus: function(tag)
49911 if (this.frame.dom.style.display == 'none') {
49912 return Roo.form.FCKeditor.superclass.focus.call(this);
49914 if(!this.el || !this.getEditor()) {
49915 this.focus.defer(100,this, [tag]);
49922 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
49923 this.getEditor().Focus();
49925 if (!this.getEditor().Selection.GetSelection()) {
49926 this.focus.defer(100,this, [tag]);
49931 var r = this.getEditor().EditorDocument.createRange();
49932 r.setStart(tgs[0],0);
49933 r.setEnd(tgs[0],0);
49934 this.getEditor().Selection.GetSelection().removeAllRanges();
49935 this.getEditor().Selection.GetSelection().addRange(r);
49936 this.getEditor().Focus();
49943 replaceTextarea : function()
49945 if ( document.getElementById( this.getId() + '___Frame' ) ) {
49948 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
49950 // We must check the elements firstly using the Id and then the name.
49951 var oTextarea = document.getElementById( this.getId() );
49953 var colElementsByName = document.getElementsByName( this.getId() ) ;
49955 oTextarea.style.display = 'none' ;
49957 if ( oTextarea.tabIndex ) {
49958 this.TabIndex = oTextarea.tabIndex ;
49961 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
49962 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
49963 this.frame = Roo.get(this.getId() + '___Frame')
49966 _getConfigHtml : function()
49970 for ( var o in this.fckconfig ) {
49971 sConfig += sConfig.length > 0 ? '&' : '';
49972 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
49975 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
49979 _getIFrameHtml : function()
49981 var sFile = 'fckeditor.html' ;
49982 /* no idea what this is about..
49985 if ( (/fcksource=true/i).test( window.top.location.search ) )
49986 sFile = 'fckeditor.original.html' ;
49991 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
49992 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
49995 var html = '<iframe id="' + this.getId() +
49996 '___Frame" src="' + sLink +
49997 '" width="' + this.width +
49998 '" height="' + this.height + '"' +
49999 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
50000 ' frameborder="0" scrolling="no"></iframe>' ;
50005 _insertHtmlBefore : function( html, element )
50007 if ( element.insertAdjacentHTML ) {
50009 element.insertAdjacentHTML( 'beforeBegin', html ) ;
50011 var oRange = document.createRange() ;
50012 oRange.setStartBefore( element ) ;
50013 var oFragment = oRange.createContextualFragment( html );
50014 element.parentNode.insertBefore( oFragment, element ) ;
50027 //Roo.reg('fckeditor', Roo.form.FCKeditor);
50029 function FCKeditor_OnComplete(editorInstance){
50030 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
50031 f.fckEditor = editorInstance;
50032 //console.log("loaded");
50033 f.fireEvent('editorinit', f, editorInstance);
50053 //<script type="text/javascript">
50055 * @class Roo.form.GridField
50056 * @extends Roo.form.Field
50057 * Embed a grid (or editable grid into a form)
50060 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
50062 * xgrid.store = Roo.data.Store
50063 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
50064 * xgrid.store.reader = Roo.data.JsonReader
50068 * Creates a new GridField
50069 * @param {Object} config Configuration options
50071 Roo.form.GridField = function(config){
50072 Roo.form.GridField.superclass.constructor.call(this, config);
50076 Roo.extend(Roo.form.GridField, Roo.form.Field, {
50078 * @cfg {Number} width - used to restrict width of grid..
50082 * @cfg {Number} height - used to restrict height of grid..
50086 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
50092 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
50093 * {tag: "input", type: "checkbox", autocomplete: "off"})
50095 // defaultAutoCreate : { tag: 'div' },
50096 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'new-password'},
50098 * @cfg {String} addTitle Text to include for adding a title.
50102 onResize : function(){
50103 Roo.form.Field.superclass.onResize.apply(this, arguments);
50106 initEvents : function(){
50107 // Roo.form.Checkbox.superclass.initEvents.call(this);
50108 // has no events...
50113 getResizeEl : function(){
50117 getPositionEl : function(){
50122 onRender : function(ct, position){
50124 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
50125 var style = this.style;
50128 Roo.form.GridField.superclass.onRender.call(this, ct, position);
50129 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
50130 this.viewEl = this.wrap.createChild({ tag: 'div' });
50132 this.viewEl.applyStyles(style);
50135 this.viewEl.setWidth(this.width);
50138 this.viewEl.setHeight(this.height);
50140 //if(this.inputValue !== undefined){
50141 //this.setValue(this.value);
50144 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
50147 this.grid.render();
50148 this.grid.getDataSource().on('remove', this.refreshValue, this);
50149 this.grid.getDataSource().on('update', this.refreshValue, this);
50150 this.grid.on('afteredit', this.refreshValue, this);
50156 * Sets the value of the item.
50157 * @param {String} either an object or a string..
50159 setValue : function(v){
50161 v = v || []; // empty set..
50162 // this does not seem smart - it really only affects memoryproxy grids..
50163 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
50164 var ds = this.grid.getDataSource();
50165 // assumes a json reader..
50167 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
50168 ds.loadData( data);
50170 // clear selection so it does not get stale.
50171 if (this.grid.sm) {
50172 this.grid.sm.clearSelections();
50175 Roo.form.GridField.superclass.setValue.call(this, v);
50176 this.refreshValue();
50177 // should load data in the grid really....
50181 refreshValue: function() {
50183 this.grid.getDataSource().each(function(r) {
50186 this.el.dom.value = Roo.encode(val);
50194 * Ext JS Library 1.1.1
50195 * Copyright(c) 2006-2007, Ext JS, LLC.
50197 * Originally Released Under LGPL - original licence link has changed is not relivant.
50200 * <script type="text/javascript">
50203 * @class Roo.form.DisplayField
50204 * @extends Roo.form.Field
50205 * A generic Field to display non-editable data.
50206 * @cfg {Boolean} closable (true|false) default false
50208 * Creates a new Display Field item.
50209 * @param {Object} config Configuration options
50211 Roo.form.DisplayField = function(config){
50212 Roo.form.DisplayField.superclass.constructor.call(this, config);
50217 * Fires after the click the close btn
50218 * @param {Roo.form.DisplayField} this
50224 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
50225 inputType: 'hidden',
50231 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
50233 focusClass : undefined,
50235 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
50237 fieldClass: 'x-form-field',
50240 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
50242 valueRenderer: undefined,
50246 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
50247 * {tag: "input", type: "checkbox", autocomplete: "off"})
50250 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
50254 onResize : function(){
50255 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
50259 initEvents : function(){
50260 // Roo.form.Checkbox.superclass.initEvents.call(this);
50261 // has no events...
50264 this.closeEl.on('click', this.onClose, this);
50270 getResizeEl : function(){
50274 getPositionEl : function(){
50279 onRender : function(ct, position){
50281 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
50282 //if(this.inputValue !== undefined){
50283 this.wrap = this.el.wrap();
50285 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
50288 this.closeEl = this.wrap.createChild({ tag: 'div', cls: 'x-dlg-close'});
50291 if (this.bodyStyle) {
50292 this.viewEl.applyStyles(this.bodyStyle);
50294 //this.viewEl.setStyle('padding', '2px');
50296 this.setValue(this.value);
50301 initValue : Roo.emptyFn,
50306 onClick : function(){
50311 * Sets the checked state of the checkbox.
50312 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
50314 setValue : function(v){
50316 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
50317 // this might be called before we have a dom element..
50318 if (!this.viewEl) {
50321 this.viewEl.dom.innerHTML = html;
50322 Roo.form.DisplayField.superclass.setValue.call(this, v);
50326 onClose : function(e)
50328 e.preventDefault();
50330 this.fireEvent('close', this);
50339 * @class Roo.form.DayPicker
50340 * @extends Roo.form.Field
50341 * A Day picker show [M] [T] [W] ....
50343 * Creates a new Day Picker
50344 * @param {Object} config Configuration options
50346 Roo.form.DayPicker= function(config){
50347 Roo.form.DayPicker.superclass.constructor.call(this, config);
50351 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
50353 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
50355 focusClass : undefined,
50357 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
50359 fieldClass: "x-form-field",
50362 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
50363 * {tag: "input", type: "checkbox", autocomplete: "off"})
50365 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "new-password"},
50368 actionMode : 'viewEl',
50372 inputType : 'hidden',
50375 inputElement: false, // real input element?
50376 basedOn: false, // ????
50378 isFormField: true, // not sure where this is needed!!!!
50380 onResize : function(){
50381 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
50382 if(!this.boxLabel){
50383 this.el.alignTo(this.wrap, 'c-c');
50387 initEvents : function(){
50388 Roo.form.Checkbox.superclass.initEvents.call(this);
50389 this.el.on("click", this.onClick, this);
50390 this.el.on("change", this.onClick, this);
50394 getResizeEl : function(){
50398 getPositionEl : function(){
50404 onRender : function(ct, position){
50405 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
50407 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
50409 var r1 = '<table><tr>';
50410 var r2 = '<tr class="x-form-daypick-icons">';
50411 for (var i=0; i < 7; i++) {
50412 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
50413 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
50416 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
50417 viewEl.select('img').on('click', this.onClick, this);
50418 this.viewEl = viewEl;
50421 // this will not work on Chrome!!!
50422 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
50423 this.el.on('propertychange', this.setFromHidden, this); //ie
50431 initValue : Roo.emptyFn,
50434 * Returns the checked state of the checkbox.
50435 * @return {Boolean} True if checked, else false
50437 getValue : function(){
50438 return this.el.dom.value;
50443 onClick : function(e){
50444 //this.setChecked(!this.checked);
50445 Roo.get(e.target).toggleClass('x-menu-item-checked');
50446 this.refreshValue();
50447 //if(this.el.dom.checked != this.checked){
50448 // this.setValue(this.el.dom.checked);
50453 refreshValue : function()
50456 this.viewEl.select('img',true).each(function(e,i,n) {
50457 val += e.is(".x-menu-item-checked") ? String(n) : '';
50459 this.setValue(val, true);
50463 * Sets the checked state of the checkbox.
50464 * On is always based on a string comparison between inputValue and the param.
50465 * @param {Boolean/String} value - the value to set
50466 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
50468 setValue : function(v,suppressEvent){
50469 if (!this.el.dom) {
50472 var old = this.el.dom.value ;
50473 this.el.dom.value = v;
50474 if (suppressEvent) {
50478 // update display..
50479 this.viewEl.select('img',true).each(function(e,i,n) {
50481 var on = e.is(".x-menu-item-checked");
50482 var newv = v.indexOf(String(n)) > -1;
50484 e.toggleClass('x-menu-item-checked');
50490 this.fireEvent('change', this, v, old);
50495 // handle setting of hidden value by some other method!!?!?
50496 setFromHidden: function()
50501 //console.log("SET FROM HIDDEN");
50502 //alert('setFrom hidden');
50503 this.setValue(this.el.dom.value);
50506 onDestroy : function()
50509 Roo.get(this.viewEl).remove();
50512 Roo.form.DayPicker.superclass.onDestroy.call(this);
50516 * RooJS Library 1.1.1
50517 * Copyright(c) 2008-2011 Alan Knowles
50524 * @class Roo.form.ComboCheck
50525 * @extends Roo.form.ComboBox
50526 * A combobox for multiple select items.
50528 * FIXME - could do with a reset button..
50531 * Create a new ComboCheck
50532 * @param {Object} config Configuration options
50534 Roo.form.ComboCheck = function(config){
50535 Roo.form.ComboCheck.superclass.constructor.call(this, config);
50536 // should verify some data...
50538 // hiddenName = required..
50539 // displayField = required
50540 // valudField == required
50541 var req= [ 'hiddenName', 'displayField', 'valueField' ];
50543 Roo.each(req, function(e) {
50544 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
50545 throw "Roo.form.ComboCheck : missing value for: " + e;
50552 Roo.extend(Roo.form.ComboCheck, Roo.form.ComboBox, {
50557 selectedClass: 'x-menu-item-checked',
50560 onRender : function(ct, position){
50566 var cls = 'x-combo-list';
50569 this.tpl = new Roo.Template({
50570 html : '<div class="'+cls+'-item x-menu-check-item">' +
50571 '<img class="x-menu-item-icon" style="margin: 0px;" src="' + Roo.BLANK_IMAGE_URL + '">' +
50572 '<span>{' + this.displayField + '}</span>' +
50579 Roo.form.ComboCheck.superclass.onRender.call(this, ct, position);
50580 this.view.singleSelect = false;
50581 this.view.multiSelect = true;
50582 this.view.toggleSelect = true;
50583 this.pageTb.add(new Roo.Toolbar.Fill(), {
50586 handler: function()
50593 onViewOver : function(e, t){
50599 onViewClick : function(doFocus,index){
50603 select: function () {
50604 //Roo.log("SELECT CALLED");
50607 selectByValue : function(xv, scrollIntoView){
50608 var ar = this.getValueArray();
50611 Roo.each(ar, function(v) {
50612 if(v === undefined || v === null){
50615 var r = this.findRecord(this.valueField, v);
50617 sels.push(this.store.indexOf(r))
50621 this.view.select(sels);
50627 onSelect : function(record, index){
50628 // Roo.log("onselect Called");
50629 // this is only called by the clear button now..
50630 this.view.clearSelections();
50631 this.setValue('[]');
50632 if (this.value != this.valueBefore) {
50633 this.fireEvent('change', this, this.value, this.valueBefore);
50634 this.valueBefore = this.value;
50637 getValueArray : function()
50642 //Roo.log(this.value);
50643 if (typeof(this.value) == 'undefined') {
50646 var ar = Roo.decode(this.value);
50647 return ar instanceof Array ? ar : []; //?? valid?
50650 Roo.log(e + "\nRoo.form.ComboCheck:getValueArray invalid data:" + this.getValue());
50655 expand : function ()
50658 Roo.form.ComboCheck.superclass.expand.call(this);
50659 this.valueBefore = typeof(this.value) == 'undefined' ? '' : this.value;
50660 //this.valueBefore = typeof(this.valueBefore) == 'undefined' ? '' : this.valueBefore;
50665 collapse : function(){
50666 Roo.form.ComboCheck.superclass.collapse.call(this);
50667 var sl = this.view.getSelectedIndexes();
50668 var st = this.store;
50672 Roo.each(sl, function(i) {
50674 nv.push(r.get(this.valueField));
50676 this.setValue(Roo.encode(nv));
50677 if (this.value != this.valueBefore) {
50679 this.fireEvent('change', this, this.value, this.valueBefore);
50680 this.valueBefore = this.value;
50685 setValue : function(v){
50689 var vals = this.getValueArray();
50691 Roo.each(vals, function(k) {
50692 var r = this.findRecord(this.valueField, k);
50694 tv.push(r.data[this.displayField]);
50695 }else if(this.valueNotFoundText !== undefined){
50696 tv.push( this.valueNotFoundText );
50701 Roo.form.ComboBox.superclass.setValue.call(this, tv.join(', '));
50702 this.hiddenField.value = v;
50708 * Ext JS Library 1.1.1
50709 * Copyright(c) 2006-2007, Ext JS, LLC.
50711 * Originally Released Under LGPL - original licence link has changed is not relivant.
50714 * <script type="text/javascript">
50718 * @class Roo.form.Signature
50719 * @extends Roo.form.Field
50723 * @param {Object} config Configuration options
50726 Roo.form.Signature = function(config){
50727 Roo.form.Signature.superclass.constructor.call(this, config);
50729 this.addEvents({// not in used??
50732 * Fires when the 'confirm' icon is pressed (add a listener to enable add button)
50733 * @param {Roo.form.Signature} combo This combo box
50738 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
50739 * @param {Roo.form.ComboBox} combo This combo box
50740 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
50746 Roo.extend(Roo.form.Signature, Roo.form.Field, {
50748 * @cfg {Object} labels Label to use when rendering a form.
50752 * confirm : "Confirm"
50757 confirm : "Confirm"
50760 * @cfg {Number} width The signature panel width (defaults to 300)
50764 * @cfg {Number} height The signature panel height (defaults to 100)
50768 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to false)
50770 allowBlank : false,
50773 // {Object} signPanel The signature SVG panel element (defaults to {})
50775 // {Boolean} isMouseDown False to validate that the mouse down event (defaults to false)
50776 isMouseDown : false,
50777 // {Boolean} isConfirmed validate the signature is confirmed or not for submitting form (defaults to false)
50778 isConfirmed : false,
50779 // {String} signatureTmp SVG mapping string (defaults to empty string)
50783 defaultAutoCreate : { // modified by initCompnoent..
50789 onRender : function(ct, position){
50791 Roo.form.Signature.superclass.onRender.call(this, ct, position);
50793 this.wrap = this.el.wrap({
50794 cls:'x-form-signature-wrap', style : 'width: ' + this.width + 'px', cn:{cls:'x-form-signature'}
50797 this.createToolbar(this);
50798 this.signPanel = this.wrap.createChild({
50800 style: 'width: ' + this.width + 'px; height: ' + this.height + 'px; border: 0;'
50804 this.svgID = Roo.id();
50805 this.svgEl = this.signPanel.createChild({
50806 xmlns : 'http://www.w3.org/2000/svg',
50808 id : this.svgID + "-svg",
50810 height: this.height,
50811 viewBox: '0 0 '+this.width+' '+this.height,
50815 id: this.svgID + "-svg-r",
50817 height: this.height,
50822 id: this.svgID + "-svg-l",
50824 y1: (this.height*0.8), // start set the line in 80% of height
50825 x2: this.width, // end
50826 y2: (this.height*0.8), // end set the line in 80% of height
50828 'stroke-width': "1",
50829 'stroke-dasharray': "3",
50830 'shape-rendering': "crispEdges",
50831 'pointer-events': "none"
50835 id: this.svgID + "-svg-p",
50837 'stroke-width': "3",
50839 'pointer-events': 'none'
50844 this.svgBox = this.svgEl.dom.getScreenCTM();
50846 createSVG : function(){
50847 var svg = this.signPanel;
50848 var r = svg.select('#'+ this.svgID + '-svg-r', true).first().dom;
50851 r.addEventListener('mousedown', function(e) { return t.down(e); }, false);
50852 r.addEventListener('mousemove', function(e) { return t.move(e); }, false);
50853 r.addEventListener('mouseup', function(e) { return t.up(e); }, false);
50854 r.addEventListener('mouseout', function(e) { return t.up(e); }, false);
50855 r.addEventListener('touchstart', function(e) { return t.down(e); }, false);
50856 r.addEventListener('touchmove', function(e) { return t.move(e); }, false);
50857 r.addEventListener('touchend', function(e) { return t.up(e); }, false);
50860 isTouchEvent : function(e){
50861 return e.type.match(/^touch/);
50863 getCoords : function (e) {
50864 var pt = this.svgEl.dom.createSVGPoint();
50867 if (this.isTouchEvent(e)) {
50868 pt.x = e.targetTouches[0].clientX;
50869 pt.y = e.targetTouches[0].clientY;
50871 var a = this.svgEl.dom.getScreenCTM();
50872 var b = a.inverse();
50873 var mx = pt.matrixTransform(b);
50874 return mx.x + ',' + mx.y;
50876 //mouse event headler
50877 down : function (e) {
50878 this.signatureTmp += 'M' + this.getCoords(e) + ' ';
50879 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr('d', this.signatureTmp);
50881 this.isMouseDown = true;
50883 e.preventDefault();
50885 move : function (e) {
50886 if (this.isMouseDown) {
50887 this.signatureTmp += 'L' + this.getCoords(e) + ' ';
50888 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', this.signatureTmp);
50891 e.preventDefault();
50893 up : function (e) {
50894 this.isMouseDown = false;
50895 var sp = this.signatureTmp.split(' ');
50898 if(!sp[sp.length-2].match(/^L/)){
50902 this.signatureTmp = sp.join(" ");
50905 if(this.getValue() != this.signatureTmp){
50906 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
50907 this.isConfirmed = false;
50909 e.preventDefault();
50913 * Protected method that will not generally be called directly. It
50914 * is called when the editor creates its toolbar. Override this method if you need to
50915 * add custom toolbar buttons.
50916 * @param {HtmlEditor} editor
50918 createToolbar : function(editor){
50919 function btn(id, toggle, handler){
50920 var xid = fid + '-'+ id ;
50924 cls : 'x-btn-icon x-edit-'+id,
50925 enableToggle:toggle !== false,
50926 scope: editor, // was editor...
50927 handler:handler||editor.relayBtnCmd,
50928 clickEvent:'mousedown',
50929 tooltip: etb.buttonTips[id] || undefined, ///tips ???
50935 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
50939 cls : ' x-signature-btn x-signature-'+id,
50940 scope: editor, // was editor...
50941 handler: this.reset,
50942 clickEvent:'mousedown',
50943 text: this.labels.clear
50950 cls : ' x-signature-btn x-signature-'+id,
50951 scope: editor, // was editor...
50952 handler: this.confirmHandler,
50953 clickEvent:'mousedown',
50954 text: this.labels.confirm
50961 * when user is clicked confirm then show this image.....
50963 * @return {String} Image Data URI
50965 getImageDataURI : function(){
50966 var svg = this.svgEl.dom.parentNode.innerHTML;
50967 var src = 'data:image/svg+xml;base64,'+window.btoa(svg);
50972 * @return {Boolean} this.isConfirmed
50974 getConfirmed : function(){
50975 return this.isConfirmed;
50979 * @return {Number} this.width
50981 getWidth : function(){
50986 * @return {Number} this.height
50988 getHeight : function(){
50989 return this.height;
50992 getSignature : function(){
50993 return this.signatureTmp;
50996 reset : function(){
50997 this.signatureTmp = '';
50998 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
50999 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', '');
51000 this.isConfirmed = false;
51001 Roo.form.Signature.superclass.reset.call(this);
51003 setSignature : function(s){
51004 this.signatureTmp = s;
51005 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
51006 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', s);
51008 this.isConfirmed = false;
51009 Roo.form.Signature.superclass.reset.call(this);
51012 // Roo.log(this.signPanel.dom.contentWindow.up())
51015 setConfirmed : function(){
51019 // Roo.log(Roo.get(this.signPanel.dom.contentWindow.r).attr('fill', '#cfc'));
51022 confirmHandler : function(){
51023 if(!this.getSignature()){
51027 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#cfc');
51028 this.setValue(this.getSignature());
51029 this.isConfirmed = true;
51031 this.fireEvent('confirm', this);
51034 // Subclasses should provide the validation implementation by overriding this
51035 validateValue : function(value){
51036 if(this.allowBlank){
51040 if(this.isConfirmed){
51047 * Ext JS Library 1.1.1
51048 * Copyright(c) 2006-2007, Ext JS, LLC.
51050 * Originally Released Under LGPL - original licence link has changed is not relivant.
51053 * <script type="text/javascript">
51058 * @class Roo.form.ComboBox
51059 * @extends Roo.form.TriggerField
51060 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
51062 * Create a new ComboBox.
51063 * @param {Object} config Configuration options
51065 Roo.form.Select = function(config){
51066 Roo.form.Select.superclass.constructor.call(this, config);
51070 Roo.extend(Roo.form.Select , Roo.form.ComboBox, {
51072 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
51075 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
51076 * rendering into an Roo.Editor, defaults to false)
51079 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
51080 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
51083 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
51086 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
51087 * the dropdown list (defaults to undefined, with no header element)
51091 * @cfg {String/Roo.Template} tpl The template to use to render the output
51095 defaultAutoCreate : {tag: "select" },
51097 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
51099 listWidth: undefined,
51101 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
51102 * mode = 'remote' or 'text' if mode = 'local')
51104 displayField: undefined,
51106 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
51107 * mode = 'remote' or 'value' if mode = 'local').
51108 * Note: use of a valueField requires the user make a selection
51109 * in order for a value to be mapped.
51111 valueField: undefined,
51115 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
51116 * field's data value (defaults to the underlying DOM element's name)
51118 hiddenName: undefined,
51120 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
51124 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
51126 selectedClass: 'x-combo-selected',
51128 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
51129 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
51130 * which displays a downward arrow icon).
51132 triggerClass : 'x-form-arrow-trigger',
51134 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
51138 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
51139 * anchor positions (defaults to 'tl-bl')
51141 listAlign: 'tl-bl?',
51143 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
51147 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
51148 * query specified by the allQuery config option (defaults to 'query')
51150 triggerAction: 'query',
51152 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
51153 * (defaults to 4, does not apply if editable = false)
51157 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
51158 * delay (typeAheadDelay) if it matches a known value (defaults to false)
51162 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
51163 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
51167 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
51168 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
51172 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
51173 * when editable = true (defaults to false)
51175 selectOnFocus:false,
51177 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
51179 queryParam: 'query',
51181 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
51182 * when mode = 'remote' (defaults to 'Loading...')
51184 loadingText: 'Loading...',
51186 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
51190 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
51194 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
51195 * traditional select (defaults to true)
51199 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
51203 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
51207 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
51208 * listWidth has a higher value)
51212 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
51213 * allow the user to set arbitrary text into the field (defaults to false)
51215 forceSelection:false,
51217 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
51218 * if typeAhead = true (defaults to 250)
51220 typeAheadDelay : 250,
51222 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
51223 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
51225 valueNotFoundText : undefined,
51228 * @cfg {String} defaultValue The value displayed after loading the store.
51233 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
51235 blockFocus : false,
51238 * @cfg {Boolean} disableClear Disable showing of clear button.
51240 disableClear : false,
51242 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
51244 alwaysQuery : false,
51250 // element that contains real text value.. (when hidden is used..)
51253 onRender : function(ct, position){
51254 Roo.form.Field.prototype.onRender.call(this, ct, position);
51257 this.store.on('beforeload', this.onBeforeLoad, this);
51258 this.store.on('load', this.onLoad, this);
51259 this.store.on('loadexception', this.onLoadException, this);
51260 this.store.load({});
51268 initEvents : function(){
51269 //Roo.form.ComboBox.superclass.initEvents.call(this);
51273 onDestroy : function(){
51276 this.store.un('beforeload', this.onBeforeLoad, this);
51277 this.store.un('load', this.onLoad, this);
51278 this.store.un('loadexception', this.onLoadException, this);
51280 //Roo.form.ComboBox.superclass.onDestroy.call(this);
51284 fireKey : function(e){
51285 if(e.isNavKeyPress() && !this.list.isVisible()){
51286 this.fireEvent("specialkey", this, e);
51291 onResize: function(w, h){
51299 * Allow or prevent the user from directly editing the field text. If false is passed,
51300 * the user will only be able to select from the items defined in the dropdown list. This method
51301 * is the runtime equivalent of setting the 'editable' config option at config time.
51302 * @param {Boolean} value True to allow the user to directly edit the field text
51304 setEditable : function(value){
51309 onBeforeLoad : function(){
51311 Roo.log("Select before load");
51314 this.innerList.update(this.loadingText ?
51315 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
51316 //this.restrictHeight();
51317 this.selectedIndex = -1;
51321 onLoad : function(){
51324 var dom = this.el.dom;
51325 dom.innerHTML = '';
51326 var od = dom.ownerDocument;
51328 if (this.emptyText) {
51329 var op = od.createElement('option');
51330 op.setAttribute('value', '');
51331 op.innerHTML = String.format('{0}', this.emptyText);
51332 dom.appendChild(op);
51334 if(this.store.getCount() > 0){
51336 var vf = this.valueField;
51337 var df = this.displayField;
51338 this.store.data.each(function(r) {
51339 // which colmsn to use... testing - cdoe / title..
51340 var op = od.createElement('option');
51341 op.setAttribute('value', r.data[vf]);
51342 op.innerHTML = String.format('{0}', r.data[df]);
51343 dom.appendChild(op);
51345 if (typeof(this.defaultValue != 'undefined')) {
51346 this.setValue(this.defaultValue);
51351 //this.onEmptyResults();
51356 onLoadException : function()
51358 dom.innerHTML = '';
51360 Roo.log("Select on load exception");
51364 Roo.log(this.store.reader.jsonData);
51365 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
51366 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
51372 onTypeAhead : function(){
51377 onSelect : function(record, index){
51378 Roo.log('on select?');
51380 if(this.fireEvent('beforeselect', this, record, index) !== false){
51381 this.setFromData(index > -1 ? record.data : false);
51383 this.fireEvent('select', this, record, index);
51388 * Returns the currently selected field value or empty string if no value is set.
51389 * @return {String} value The selected value
51391 getValue : function(){
51392 var dom = this.el.dom;
51393 this.value = dom.options[dom.selectedIndex].value;
51399 * Clears any text/value currently set in the field
51401 clearValue : function(){
51403 this.el.dom.selectedIndex = this.emptyText ? 0 : -1;
51408 * Sets the specified value into the field. If the value finds a match, the corresponding record text
51409 * will be displayed in the field. If the value does not match the data value of an existing item,
51410 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
51411 * Otherwise the field will be blank (although the value will still be set).
51412 * @param {String} value The value to match
51414 setValue : function(v){
51415 var d = this.el.dom;
51416 for (var i =0; i < d.options.length;i++) {
51417 if (v == d.options[i].value) {
51418 d.selectedIndex = i;
51426 * @property {Object} the last set data for the element
51431 * Sets the value of the field based on a object which is related to the record format for the store.
51432 * @param {Object} value the value to set as. or false on reset?
51434 setFromData : function(o){
51435 Roo.log('setfrom data?');
51441 reset : function(){
51445 findRecord : function(prop, value){
51450 if(this.store.getCount() > 0){
51451 this.store.each(function(r){
51452 if(r.data[prop] == value){
51462 getName: function()
51464 // returns hidden if it's set..
51465 if (!this.rendered) {return ''};
51466 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
51474 onEmptyResults : function(){
51475 Roo.log('empty results');
51480 * Returns true if the dropdown list is expanded, else false.
51482 isExpanded : function(){
51487 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
51488 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
51489 * @param {String} value The data value of the item to select
51490 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
51491 * selected item if it is not currently in view (defaults to true)
51492 * @return {Boolean} True if the value matched an item in the list, else false
51494 selectByValue : function(v, scrollIntoView){
51495 Roo.log('select By Value');
51498 if(v !== undefined && v !== null){
51499 var r = this.findRecord(this.valueField || this.displayField, v);
51501 this.select(this.store.indexOf(r), scrollIntoView);
51509 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
51510 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
51511 * @param {Number} index The zero-based index of the list item to select
51512 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
51513 * selected item if it is not currently in view (defaults to true)
51515 select : function(index, scrollIntoView){
51516 Roo.log('select ');
51519 this.selectedIndex = index;
51520 this.view.select(index);
51521 if(scrollIntoView !== false){
51522 var el = this.view.getNode(index);
51524 this.innerList.scrollChildIntoView(el, false);
51532 validateBlur : function(){
51539 initQuery : function(){
51540 this.doQuery(this.getRawValue());
51544 doForce : function(){
51545 if(this.el.dom.value.length > 0){
51546 this.el.dom.value =
51547 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
51553 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
51554 * query allowing the query action to be canceled if needed.
51555 * @param {String} query The SQL query to execute
51556 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
51557 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
51558 * saved in the current store (defaults to false)
51560 doQuery : function(q, forceAll){
51562 Roo.log('doQuery?');
51563 if(q === undefined || q === null){
51568 forceAll: forceAll,
51572 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
51576 forceAll = qe.forceAll;
51577 if(forceAll === true || (q.length >= this.minChars)){
51578 if(this.lastQuery != q || this.alwaysQuery){
51579 this.lastQuery = q;
51580 if(this.mode == 'local'){
51581 this.selectedIndex = -1;
51583 this.store.clearFilter();
51585 this.store.filter(this.displayField, q);
51589 this.store.baseParams[this.queryParam] = q;
51591 params: this.getParams(q)
51596 this.selectedIndex = -1;
51603 getParams : function(q){
51605 //p[this.queryParam] = q;
51608 p.limit = this.pageSize;
51614 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
51616 collapse : function(){
51621 collapseIf : function(e){
51626 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
51628 expand : function(){
51636 * @cfg {Boolean} grow
51640 * @cfg {Number} growMin
51644 * @cfg {Number} growMax
51652 setWidth : function()
51656 getResizeEl : function(){
51659 });//<script type="text/javasscript">
51663 * @class Roo.DDView
51664 * A DnD enabled version of Roo.View.
51665 * @param {Element/String} container The Element in which to create the View.
51666 * @param {String} tpl The template string used to create the markup for each element of the View
51667 * @param {Object} config The configuration properties. These include all the config options of
51668 * {@link Roo.View} plus some specific to this class.<br>
51670 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
51671 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
51673 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
51674 .x-view-drag-insert-above {
51675 border-top:1px dotted #3366cc;
51677 .x-view-drag-insert-below {
51678 border-bottom:1px dotted #3366cc;
51684 Roo.DDView = function(container, tpl, config) {
51685 Roo.DDView.superclass.constructor.apply(this, arguments);
51686 this.getEl().setStyle("outline", "0px none");
51687 this.getEl().unselectable();
51688 if (this.dragGroup) {
51689 this.setDraggable(this.dragGroup.split(","));
51691 if (this.dropGroup) {
51692 this.setDroppable(this.dropGroup.split(","));
51694 if (this.deletable) {
51695 this.setDeletable();
51697 this.isDirtyFlag = false;
51703 Roo.extend(Roo.DDView, Roo.View, {
51704 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
51705 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
51706 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
51707 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
51711 reset: Roo.emptyFn,
51713 clearInvalid: Roo.form.Field.prototype.clearInvalid,
51715 validate: function() {
51719 destroy: function() {
51720 this.purgeListeners();
51721 this.getEl.removeAllListeners();
51722 this.getEl().remove();
51723 if (this.dragZone) {
51724 if (this.dragZone.destroy) {
51725 this.dragZone.destroy();
51728 if (this.dropZone) {
51729 if (this.dropZone.destroy) {
51730 this.dropZone.destroy();
51735 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
51736 getName: function() {
51740 /** Loads the View from a JSON string representing the Records to put into the Store. */
51741 setValue: function(v) {
51743 throw "DDView.setValue(). DDView must be constructed with a valid Store";
51746 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
51747 this.store.proxy = new Roo.data.MemoryProxy(data);
51751 /** @return {String} a parenthesised list of the ids of the Records in the View. */
51752 getValue: function() {
51754 this.store.each(function(rec) {
51755 result += rec.id + ',';
51757 return result.substr(0, result.length - 1) + ')';
51760 getIds: function() {
51761 var i = 0, result = new Array(this.store.getCount());
51762 this.store.each(function(rec) {
51763 result[i++] = rec.id;
51768 isDirty: function() {
51769 return this.isDirtyFlag;
51773 * Part of the Roo.dd.DropZone interface. If no target node is found, the
51774 * whole Element becomes the target, and this causes the drop gesture to append.
51776 getTargetFromEvent : function(e) {
51777 var target = e.getTarget();
51778 while ((target !== null) && (target.parentNode != this.el.dom)) {
51779 target = target.parentNode;
51782 target = this.el.dom.lastChild || this.el.dom;
51788 * Create the drag data which consists of an object which has the property "ddel" as
51789 * the drag proxy element.
51791 getDragData : function(e) {
51792 var target = this.findItemFromChild(e.getTarget());
51794 this.handleSelection(e);
51795 var selNodes = this.getSelectedNodes();
51798 copy: this.copy || (this.allowCopy && e.ctrlKey),
51802 var selectedIndices = this.getSelectedIndexes();
51803 for (var i = 0; i < selectedIndices.length; i++) {
51804 dragData.records.push(this.store.getAt(selectedIndices[i]));
51806 if (selNodes.length == 1) {
51807 dragData.ddel = target.cloneNode(true); // the div element
51809 var div = document.createElement('div'); // create the multi element drag "ghost"
51810 div.className = 'multi-proxy';
51811 for (var i = 0, len = selNodes.length; i < len; i++) {
51812 div.appendChild(selNodes[i].cloneNode(true));
51814 dragData.ddel = div;
51816 //console.log(dragData)
51817 //console.log(dragData.ddel.innerHTML)
51820 //console.log('nodragData')
51824 /** Specify to which ddGroup items in this DDView may be dragged. */
51825 setDraggable: function(ddGroup) {
51826 if (ddGroup instanceof Array) {
51827 Roo.each(ddGroup, this.setDraggable, this);
51830 if (this.dragZone) {
51831 this.dragZone.addToGroup(ddGroup);
51833 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
51834 containerScroll: true,
51838 // Draggability implies selection. DragZone's mousedown selects the element.
51839 if (!this.multiSelect) { this.singleSelect = true; }
51841 // Wire the DragZone's handlers up to methods in *this*
51842 this.dragZone.getDragData = this.getDragData.createDelegate(this);
51846 /** Specify from which ddGroup this DDView accepts drops. */
51847 setDroppable: function(ddGroup) {
51848 if (ddGroup instanceof Array) {
51849 Roo.each(ddGroup, this.setDroppable, this);
51852 if (this.dropZone) {
51853 this.dropZone.addToGroup(ddGroup);
51855 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
51856 containerScroll: true,
51860 // Wire the DropZone's handlers up to methods in *this*
51861 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
51862 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
51863 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
51864 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
51865 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
51869 /** Decide whether to drop above or below a View node. */
51870 getDropPoint : function(e, n, dd){
51871 if (n == this.el.dom) { return "above"; }
51872 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
51873 var c = t + (b - t) / 2;
51874 var y = Roo.lib.Event.getPageY(e);
51882 onNodeEnter : function(n, dd, e, data){
51886 onNodeOver : function(n, dd, e, data){
51887 var pt = this.getDropPoint(e, n, dd);
51888 // set the insert point style on the target node
51889 var dragElClass = this.dropNotAllowed;
51892 if (pt == "above"){
51893 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
51894 targetElClass = "x-view-drag-insert-above";
51896 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
51897 targetElClass = "x-view-drag-insert-below";
51899 if (this.lastInsertClass != targetElClass){
51900 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
51901 this.lastInsertClass = targetElClass;
51904 return dragElClass;
51907 onNodeOut : function(n, dd, e, data){
51908 this.removeDropIndicators(n);
51911 onNodeDrop : function(n, dd, e, data){
51912 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
51915 var pt = this.getDropPoint(e, n, dd);
51916 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
51917 if (pt == "below") { insertAt++; }
51918 for (var i = 0; i < data.records.length; i++) {
51919 var r = data.records[i];
51920 var dup = this.store.getById(r.id);
51921 if (dup && (dd != this.dragZone)) {
51922 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
51925 this.store.insert(insertAt++, r.copy());
51927 data.source.isDirtyFlag = true;
51929 this.store.insert(insertAt++, r);
51931 this.isDirtyFlag = true;
51934 this.dragZone.cachedTarget = null;
51938 removeDropIndicators : function(n){
51940 Roo.fly(n).removeClass([
51941 "x-view-drag-insert-above",
51942 "x-view-drag-insert-below"]);
51943 this.lastInsertClass = "_noclass";
51948 * Utility method. Add a delete option to the DDView's context menu.
51949 * @param {String} imageUrl The URL of the "delete" icon image.
51951 setDeletable: function(imageUrl) {
51952 if (!this.singleSelect && !this.multiSelect) {
51953 this.singleSelect = true;
51955 var c = this.getContextMenu();
51956 this.contextMenu.on("itemclick", function(item) {
51959 this.remove(this.getSelectedIndexes());
51963 this.contextMenu.add({
51970 /** Return the context menu for this DDView. */
51971 getContextMenu: function() {
51972 if (!this.contextMenu) {
51973 // Create the View's context menu
51974 this.contextMenu = new Roo.menu.Menu({
51975 id: this.id + "-contextmenu"
51977 this.el.on("contextmenu", this.showContextMenu, this);
51979 return this.contextMenu;
51982 disableContextMenu: function() {
51983 if (this.contextMenu) {
51984 this.el.un("contextmenu", this.showContextMenu, this);
51988 showContextMenu: function(e, item) {
51989 item = this.findItemFromChild(e.getTarget());
51992 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
51993 this.contextMenu.showAt(e.getXY());
51998 * Remove {@link Roo.data.Record}s at the specified indices.
51999 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
52001 remove: function(selectedIndices) {
52002 selectedIndices = [].concat(selectedIndices);
52003 for (var i = 0; i < selectedIndices.length; i++) {
52004 var rec = this.store.getAt(selectedIndices[i]);
52005 this.store.remove(rec);
52010 * Double click fires the event, but also, if this is draggable, and there is only one other
52011 * related DropZone, it transfers the selected node.
52013 onDblClick : function(e){
52014 var item = this.findItemFromChild(e.getTarget());
52016 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
52019 if (this.dragGroup) {
52020 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
52021 while (targets.indexOf(this.dropZone) > -1) {
52022 targets.remove(this.dropZone);
52024 if (targets.length == 1) {
52025 this.dragZone.cachedTarget = null;
52026 var el = Roo.get(targets[0].getEl());
52027 var box = el.getBox(true);
52028 targets[0].onNodeDrop(el.dom, {
52030 xy: [box.x, box.y + box.height - 1]
52031 }, null, this.getDragData(e));
52037 handleSelection: function(e) {
52038 this.dragZone.cachedTarget = null;
52039 var item = this.findItemFromChild(e.getTarget());
52041 this.clearSelections(true);
52044 if (item && (this.multiSelect || this.singleSelect)){
52045 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
52046 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
52047 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
52048 this.unselect(item);
52050 this.select(item, this.multiSelect && e.ctrlKey);
52051 this.lastSelection = item;
52056 onItemClick : function(item, index, e){
52057 if(this.fireEvent("beforeclick", this, index, item, e) === false){
52063 unselect : function(nodeInfo, suppressEvent){
52064 var node = this.getNode(nodeInfo);
52065 if(node && this.isSelected(node)){
52066 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
52067 Roo.fly(node).removeClass(this.selectedClass);
52068 this.selections.remove(node);
52069 if(!suppressEvent){
52070 this.fireEvent("selectionchange", this, this.selections);
52078 * Ext JS Library 1.1.1
52079 * Copyright(c) 2006-2007, Ext JS, LLC.
52081 * Originally Released Under LGPL - original licence link has changed is not relivant.
52084 * <script type="text/javascript">
52088 * @class Roo.LayoutManager
52089 * @extends Roo.util.Observable
52090 * Base class for layout managers.
52092 Roo.LayoutManager = function(container, config){
52093 Roo.LayoutManager.superclass.constructor.call(this);
52094 this.el = Roo.get(container);
52095 // ie scrollbar fix
52096 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
52097 document.body.scroll = "no";
52098 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
52099 this.el.position('relative');
52101 this.id = this.el.id;
52102 this.el.addClass("x-layout-container");
52103 /** false to disable window resize monitoring @type Boolean */
52104 this.monitorWindowResize = true;
52109 * Fires when a layout is performed.
52110 * @param {Roo.LayoutManager} this
52114 * @event regionresized
52115 * Fires when the user resizes a region.
52116 * @param {Roo.LayoutRegion} region The resized region
52117 * @param {Number} newSize The new size (width for east/west, height for north/south)
52119 "regionresized" : true,
52121 * @event regioncollapsed
52122 * Fires when a region is collapsed.
52123 * @param {Roo.LayoutRegion} region The collapsed region
52125 "regioncollapsed" : true,
52127 * @event regionexpanded
52128 * Fires when a region is expanded.
52129 * @param {Roo.LayoutRegion} region The expanded region
52131 "regionexpanded" : true
52133 this.updating = false;
52134 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
52137 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
52139 * Returns true if this layout is currently being updated
52140 * @return {Boolean}
52142 isUpdating : function(){
52143 return this.updating;
52147 * Suspend the LayoutManager from doing auto-layouts while
52148 * making multiple add or remove calls
52150 beginUpdate : function(){
52151 this.updating = true;
52155 * Restore auto-layouts and optionally disable the manager from performing a layout
52156 * @param {Boolean} noLayout true to disable a layout update
52158 endUpdate : function(noLayout){
52159 this.updating = false;
52165 layout: function(){
52169 onRegionResized : function(region, newSize){
52170 this.fireEvent("regionresized", region, newSize);
52174 onRegionCollapsed : function(region){
52175 this.fireEvent("regioncollapsed", region);
52178 onRegionExpanded : function(region){
52179 this.fireEvent("regionexpanded", region);
52183 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
52184 * performs box-model adjustments.
52185 * @return {Object} The size as an object {width: (the width), height: (the height)}
52187 getViewSize : function(){
52189 if(this.el.dom != document.body){
52190 size = this.el.getSize();
52192 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
52194 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
52195 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
52200 * Returns the Element this layout is bound to.
52201 * @return {Roo.Element}
52203 getEl : function(){
52208 * Returns the specified region.
52209 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
52210 * @return {Roo.LayoutRegion}
52212 getRegion : function(target){
52213 return this.regions[target.toLowerCase()];
52216 onWindowResize : function(){
52217 if(this.monitorWindowResize){
52223 * Ext JS Library 1.1.1
52224 * Copyright(c) 2006-2007, Ext JS, LLC.
52226 * Originally Released Under LGPL - original licence link has changed is not relivant.
52229 * <script type="text/javascript">
52232 * @class Roo.BorderLayout
52233 * @extends Roo.LayoutManager
52234 * @children Roo.ContentPanel
52235 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
52236 * please see: <br><br>
52237 * <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>
52238 * <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>
52241 var layout = new Roo.BorderLayout(document.body, {
52275 preferredTabWidth: 150
52280 var CP = Roo.ContentPanel;
52282 layout.beginUpdate();
52283 layout.add("north", new CP("north", "North"));
52284 layout.add("south", new CP("south", {title: "South", closable: true}));
52285 layout.add("west", new CP("west", {title: "West"}));
52286 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
52287 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
52288 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
52289 layout.getRegion("center").showPanel("center1");
52290 layout.endUpdate();
52293 <b>The container the layout is rendered into can be either the body element or any other element.
52294 If it is not the body element, the container needs to either be an absolute positioned element,
52295 or you will need to add "position:relative" to the css of the container. You will also need to specify
52296 the container size if it is not the body element.</b>
52299 * Create a new BorderLayout
52300 * @param {String/HTMLElement/Element} container The container this layout is bound to
52301 * @param {Object} config Configuration options
52303 Roo.BorderLayout = function(container, config){
52304 config = config || {};
52305 Roo.BorderLayout.superclass.constructor.call(this, container, config);
52306 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
52307 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
52308 var target = this.factory.validRegions[i];
52309 if(config[target]){
52310 this.addRegion(target, config[target]);
52315 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
52318 * @cfg {Roo.LayoutRegion} east
52321 * @cfg {Roo.LayoutRegion} west
52324 * @cfg {Roo.LayoutRegion} north
52327 * @cfg {Roo.LayoutRegion} south
52330 * @cfg {Roo.LayoutRegion} center
52333 * Creates and adds a new region if it doesn't already exist.
52334 * @param {String} target The target region key (north, south, east, west or center).
52335 * @param {Object} config The regions config object
52336 * @return {BorderLayoutRegion} The new region
52338 addRegion : function(target, config){
52339 if(!this.regions[target]){
52340 var r = this.factory.create(target, this, config);
52341 this.bindRegion(target, r);
52343 return this.regions[target];
52347 bindRegion : function(name, r){
52348 this.regions[name] = r;
52349 r.on("visibilitychange", this.layout, this);
52350 r.on("paneladded", this.layout, this);
52351 r.on("panelremoved", this.layout, this);
52352 r.on("invalidated", this.layout, this);
52353 r.on("resized", this.onRegionResized, this);
52354 r.on("collapsed", this.onRegionCollapsed, this);
52355 r.on("expanded", this.onRegionExpanded, this);
52359 * Performs a layout update.
52361 layout : function(){
52362 if(this.updating) {
52365 var size = this.getViewSize();
52366 var w = size.width;
52367 var h = size.height;
52372 //var x = 0, y = 0;
52374 var rs = this.regions;
52375 var north = rs["north"];
52376 var south = rs["south"];
52377 var west = rs["west"];
52378 var east = rs["east"];
52379 var center = rs["center"];
52380 //if(this.hideOnLayout){ // not supported anymore
52381 //c.el.setStyle("display", "none");
52383 if(north && north.isVisible()){
52384 var b = north.getBox();
52385 var m = north.getMargins();
52386 b.width = w - (m.left+m.right);
52389 centerY = b.height + b.y + m.bottom;
52390 centerH -= centerY;
52391 north.updateBox(this.safeBox(b));
52393 if(south && south.isVisible()){
52394 var b = south.getBox();
52395 var m = south.getMargins();
52396 b.width = w - (m.left+m.right);
52398 var totalHeight = (b.height + m.top + m.bottom);
52399 b.y = h - totalHeight + m.top;
52400 centerH -= totalHeight;
52401 south.updateBox(this.safeBox(b));
52403 if(west && west.isVisible()){
52404 var b = west.getBox();
52405 var m = west.getMargins();
52406 b.height = centerH - (m.top+m.bottom);
52408 b.y = centerY + m.top;
52409 var totalWidth = (b.width + m.left + m.right);
52410 centerX += totalWidth;
52411 centerW -= totalWidth;
52412 west.updateBox(this.safeBox(b));
52414 if(east && east.isVisible()){
52415 var b = east.getBox();
52416 var m = east.getMargins();
52417 b.height = centerH - (m.top+m.bottom);
52418 var totalWidth = (b.width + m.left + m.right);
52419 b.x = w - totalWidth + m.left;
52420 b.y = centerY + m.top;
52421 centerW -= totalWidth;
52422 east.updateBox(this.safeBox(b));
52425 var m = center.getMargins();
52427 x: centerX + m.left,
52428 y: centerY + m.top,
52429 width: centerW - (m.left+m.right),
52430 height: centerH - (m.top+m.bottom)
52432 //if(this.hideOnLayout){
52433 //center.el.setStyle("display", "block");
52435 center.updateBox(this.safeBox(centerBox));
52438 this.fireEvent("layout", this);
52442 safeBox : function(box){
52443 box.width = Math.max(0, box.width);
52444 box.height = Math.max(0, box.height);
52449 * Adds a ContentPanel (or subclass) to this layout.
52450 * @param {String} target The target region key (north, south, east, west or center).
52451 * @param {Roo.ContentPanel} panel The panel to add
52452 * @return {Roo.ContentPanel} The added panel
52454 add : function(target, panel){
52456 target = target.toLowerCase();
52457 return this.regions[target].add(panel);
52461 * Remove a ContentPanel (or subclass) to this layout.
52462 * @param {String} target The target region key (north, south, east, west or center).
52463 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
52464 * @return {Roo.ContentPanel} The removed panel
52466 remove : function(target, panel){
52467 target = target.toLowerCase();
52468 return this.regions[target].remove(panel);
52472 * Searches all regions for a panel with the specified id
52473 * @param {String} panelId
52474 * @return {Roo.ContentPanel} The panel or null if it wasn't found
52476 findPanel : function(panelId){
52477 var rs = this.regions;
52478 for(var target in rs){
52479 if(typeof rs[target] != "function"){
52480 var p = rs[target].getPanel(panelId);
52490 * Searches all regions for a panel with the specified id and activates (shows) it.
52491 * @param {String/ContentPanel} panelId The panels id or the panel itself
52492 * @return {Roo.ContentPanel} The shown panel or null
52494 showPanel : function(panelId) {
52495 var rs = this.regions;
52496 for(var target in rs){
52497 var r = rs[target];
52498 if(typeof r != "function"){
52499 if(r.hasPanel(panelId)){
52500 return r.showPanel(panelId);
52508 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
52509 * @param {Roo.state.Provider} provider (optional) An alternate state provider
52511 restoreState : function(provider){
52513 provider = Roo.state.Manager;
52515 var sm = new Roo.LayoutStateManager();
52516 sm.init(this, provider);
52520 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
52521 * object should contain properties for each region to add ContentPanels to, and each property's value should be
52522 * a valid ContentPanel config object. Example:
52524 // Create the main layout
52525 var layout = new Roo.BorderLayout('main-ct', {
52536 // Create and add multiple ContentPanels at once via configs
52539 id: 'source-files',
52541 title:'Ext Source Files',
52554 * @param {Object} regions An object containing ContentPanel configs by region name
52556 batchAdd : function(regions){
52557 this.beginUpdate();
52558 for(var rname in regions){
52559 var lr = this.regions[rname];
52561 this.addTypedPanels(lr, regions[rname]);
52568 addTypedPanels : function(lr, ps){
52569 if(typeof ps == 'string'){
52570 lr.add(new Roo.ContentPanel(ps));
52572 else if(ps instanceof Array){
52573 for(var i =0, len = ps.length; i < len; i++){
52574 this.addTypedPanels(lr, ps[i]);
52577 else if(!ps.events){ // raw config?
52579 delete ps.el; // prevent conflict
52580 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
52582 else { // panel object assumed!
52587 * Adds a xtype elements to the layout.
52591 xtype : 'ContentPanel',
52598 xtype : 'NestedLayoutPanel',
52604 items : [ ... list of content panels or nested layout panels.. ]
52608 * @param {Object} cfg Xtype definition of item to add.
52610 addxtype : function(cfg)
52612 // basically accepts a pannel...
52613 // can accept a layout region..!?!?
52614 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
52616 if (!cfg.xtype.match(/Panel$/)) {
52621 if (typeof(cfg.region) == 'undefined') {
52622 Roo.log("Failed to add Panel, region was not set");
52626 var region = cfg.region;
52632 xitems = cfg.items;
52639 case 'ContentPanel': // ContentPanel (el, cfg)
52640 case 'ScrollPanel': // ContentPanel (el, cfg)
52642 if(cfg.autoCreate) {
52643 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
52645 var el = this.el.createChild();
52646 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
52649 this.add(region, ret);
52653 case 'TreePanel': // our new panel!
52654 cfg.el = this.el.createChild();
52655 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
52656 this.add(region, ret);
52659 case 'NestedLayoutPanel':
52660 // create a new Layout (which is a Border Layout...
52661 var el = this.el.createChild();
52662 var clayout = cfg.layout;
52664 clayout.items = clayout.items || [];
52665 // replace this exitems with the clayout ones..
52666 xitems = clayout.items;
52669 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
52670 cfg.background = false;
52672 var layout = new Roo.BorderLayout(el, clayout);
52674 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
52675 //console.log('adding nested layout panel ' + cfg.toSource());
52676 this.add(region, ret);
52677 nb = {}; /// find first...
52682 // needs grid and region
52684 //var el = this.getRegion(region).el.createChild();
52685 var el = this.el.createChild();
52686 // create the grid first...
52688 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
52690 if (region == 'center' && this.active ) {
52691 cfg.background = false;
52693 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
52695 this.add(region, ret);
52696 if (cfg.background) {
52697 ret.on('activate', function(gp) {
52698 if (!gp.grid.rendered) {
52713 if (typeof(Roo[cfg.xtype]) != 'undefined') {
52715 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
52716 this.add(region, ret);
52719 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
52723 // GridPanel (grid, cfg)
52726 this.beginUpdate();
52730 Roo.each(xitems, function(i) {
52731 region = nb && i.region ? i.region : false;
52733 var add = ret.addxtype(i);
52736 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
52737 if (!i.background) {
52738 abn[region] = nb[region] ;
52745 // make the last non-background panel active..
52746 //if (nb) { Roo.log(abn); }
52749 for(var r in abn) {
52750 region = this.getRegion(r);
52752 // tried using nb[r], but it does not work..
52754 region.showPanel(abn[r]);
52765 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
52766 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
52767 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
52768 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
52771 var CP = Roo.ContentPanel;
52773 var layout = Roo.BorderLayout.create({
52777 panels: [new CP("north", "North")]
52786 panels: [new CP("west", {title: "West"})]
52795 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
52804 panels: [new CP("south", {title: "South", closable: true})]
52811 preferredTabWidth: 150,
52813 new CP("center1", {title: "Close Me", closable: true}),
52814 new CP("center2", {title: "Center Panel", closable: false})
52819 layout.getRegion("center").showPanel("center1");
52824 Roo.BorderLayout.create = function(config, targetEl){
52825 var layout = new Roo.BorderLayout(targetEl || document.body, config);
52826 layout.beginUpdate();
52827 var regions = Roo.BorderLayout.RegionFactory.validRegions;
52828 for(var j = 0, jlen = regions.length; j < jlen; j++){
52829 var lr = regions[j];
52830 if(layout.regions[lr] && config[lr].panels){
52831 var r = layout.regions[lr];
52832 var ps = config[lr].panels;
52833 layout.addTypedPanels(r, ps);
52836 layout.endUpdate();
52841 Roo.BorderLayout.RegionFactory = {
52843 validRegions : ["north","south","east","west","center"],
52846 create : function(target, mgr, config){
52847 target = target.toLowerCase();
52848 if(config.lightweight || config.basic){
52849 return new Roo.BasicLayoutRegion(mgr, config, target);
52853 return new Roo.NorthLayoutRegion(mgr, config);
52855 return new Roo.SouthLayoutRegion(mgr, config);
52857 return new Roo.EastLayoutRegion(mgr, config);
52859 return new Roo.WestLayoutRegion(mgr, config);
52861 return new Roo.CenterLayoutRegion(mgr, config);
52863 throw 'Layout region "'+target+'" not supported.';
52867 * Ext JS Library 1.1.1
52868 * Copyright(c) 2006-2007, Ext JS, LLC.
52870 * Originally Released Under LGPL - original licence link has changed is not relivant.
52873 * <script type="text/javascript">
52877 * @class Roo.BasicLayoutRegion
52878 * @extends Roo.util.Observable
52879 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
52880 * and does not have a titlebar, tabs or any other features. All it does is size and position
52881 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
52883 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
52885 this.position = pos;
52888 * @scope Roo.BasicLayoutRegion
52892 * @event beforeremove
52893 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
52894 * @param {Roo.LayoutRegion} this
52895 * @param {Roo.ContentPanel} panel The panel
52896 * @param {Object} e The cancel event object
52898 "beforeremove" : true,
52900 * @event invalidated
52901 * Fires when the layout for this region is changed.
52902 * @param {Roo.LayoutRegion} this
52904 "invalidated" : true,
52906 * @event visibilitychange
52907 * Fires when this region is shown or hidden
52908 * @param {Roo.LayoutRegion} this
52909 * @param {Boolean} visibility true or false
52911 "visibilitychange" : true,
52913 * @event paneladded
52914 * Fires when a panel is added.
52915 * @param {Roo.LayoutRegion} this
52916 * @param {Roo.ContentPanel} panel The panel
52918 "paneladded" : true,
52920 * @event panelremoved
52921 * Fires when a panel is removed.
52922 * @param {Roo.LayoutRegion} this
52923 * @param {Roo.ContentPanel} panel The panel
52925 "panelremoved" : true,
52927 * @event beforecollapse
52928 * Fires when this region before collapse.
52929 * @param {Roo.LayoutRegion} this
52931 "beforecollapse" : true,
52934 * Fires when this region is collapsed.
52935 * @param {Roo.LayoutRegion} this
52937 "collapsed" : true,
52940 * Fires when this region is expanded.
52941 * @param {Roo.LayoutRegion} this
52946 * Fires when this region is slid into view.
52947 * @param {Roo.LayoutRegion} this
52949 "slideshow" : true,
52952 * Fires when this region slides out of view.
52953 * @param {Roo.LayoutRegion} this
52955 "slidehide" : true,
52957 * @event panelactivated
52958 * Fires when a panel is activated.
52959 * @param {Roo.LayoutRegion} this
52960 * @param {Roo.ContentPanel} panel The activated panel
52962 "panelactivated" : true,
52965 * Fires when the user resizes this region.
52966 * @param {Roo.LayoutRegion} this
52967 * @param {Number} newSize The new size (width for east/west, height for north/south)
52971 /** A collection of panels in this region. @type Roo.util.MixedCollection */
52972 this.panels = new Roo.util.MixedCollection();
52973 this.panels.getKey = this.getPanelId.createDelegate(this);
52975 this.activePanel = null;
52976 // ensure listeners are added...
52978 if (config.listeners || config.events) {
52979 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
52980 listeners : config.listeners || {},
52981 events : config.events || {}
52985 if(skipConfig !== true){
52986 this.applyConfig(config);
52990 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
52991 getPanelId : function(p){
52995 applyConfig : function(config){
52996 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
52997 this.config = config;
53002 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
53003 * the width, for horizontal (north, south) the height.
53004 * @param {Number} newSize The new width or height
53006 resizeTo : function(newSize){
53007 var el = this.el ? this.el :
53008 (this.activePanel ? this.activePanel.getEl() : null);
53010 switch(this.position){
53013 el.setWidth(newSize);
53014 this.fireEvent("resized", this, newSize);
53018 el.setHeight(newSize);
53019 this.fireEvent("resized", this, newSize);
53025 getBox : function(){
53026 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
53029 getMargins : function(){
53030 return this.margins;
53033 updateBox : function(box){
53035 var el = this.activePanel.getEl();
53036 el.dom.style.left = box.x + "px";
53037 el.dom.style.top = box.y + "px";
53038 this.activePanel.setSize(box.width, box.height);
53042 * Returns the container element for this region.
53043 * @return {Roo.Element}
53045 getEl : function(){
53046 return this.activePanel;
53050 * Returns true if this region is currently visible.
53051 * @return {Boolean}
53053 isVisible : function(){
53054 return this.activePanel ? true : false;
53057 setActivePanel : function(panel){
53058 panel = this.getPanel(panel);
53059 if(this.activePanel && this.activePanel != panel){
53060 this.activePanel.setActiveState(false);
53061 this.activePanel.getEl().setLeftTop(-10000,-10000);
53063 this.activePanel = panel;
53064 panel.setActiveState(true);
53066 panel.setSize(this.box.width, this.box.height);
53068 this.fireEvent("panelactivated", this, panel);
53069 this.fireEvent("invalidated");
53073 * Show the specified panel.
53074 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
53075 * @return {Roo.ContentPanel} The shown panel or null
53077 showPanel : function(panel){
53078 if(panel = this.getPanel(panel)){
53079 this.setActivePanel(panel);
53085 * Get the active panel for this region.
53086 * @return {Roo.ContentPanel} The active panel or null
53088 getActivePanel : function(){
53089 return this.activePanel;
53093 * Add the passed ContentPanel(s)
53094 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
53095 * @return {Roo.ContentPanel} The panel added (if only one was added)
53097 add : function(panel){
53098 if(arguments.length > 1){
53099 for(var i = 0, len = arguments.length; i < len; i++) {
53100 this.add(arguments[i]);
53104 if(this.hasPanel(panel)){
53105 this.showPanel(panel);
53108 var el = panel.getEl();
53109 if(el.dom.parentNode != this.mgr.el.dom){
53110 this.mgr.el.dom.appendChild(el.dom);
53112 if(panel.setRegion){
53113 panel.setRegion(this);
53115 this.panels.add(panel);
53116 el.setStyle("position", "absolute");
53117 if(!panel.background){
53118 this.setActivePanel(panel);
53119 if(this.config.initialSize && this.panels.getCount()==1){
53120 this.resizeTo(this.config.initialSize);
53123 this.fireEvent("paneladded", this, panel);
53128 * Returns true if the panel is in this region.
53129 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
53130 * @return {Boolean}
53132 hasPanel : function(panel){
53133 if(typeof panel == "object"){ // must be panel obj
53134 panel = panel.getId();
53136 return this.getPanel(panel) ? true : false;
53140 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
53141 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
53142 * @param {Boolean} preservePanel Overrides the config preservePanel option
53143 * @return {Roo.ContentPanel} The panel that was removed
53145 remove : function(panel, preservePanel){
53146 panel = this.getPanel(panel);
53151 this.fireEvent("beforeremove", this, panel, e);
53152 if(e.cancel === true){
53155 var panelId = panel.getId();
53156 this.panels.removeKey(panelId);
53161 * Returns the panel specified or null if it's not in this region.
53162 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
53163 * @return {Roo.ContentPanel}
53165 getPanel : function(id){
53166 if(typeof id == "object"){ // must be panel obj
53169 return this.panels.get(id);
53173 * Returns this regions position (north/south/east/west/center).
53176 getPosition: function(){
53177 return this.position;
53181 * Ext JS Library 1.1.1
53182 * Copyright(c) 2006-2007, Ext JS, LLC.
53184 * Originally Released Under LGPL - original licence link has changed is not relivant.
53187 * <script type="text/javascript">
53191 * @class Roo.LayoutRegion
53192 * @extends Roo.BasicLayoutRegion
53193 * This class represents a region in a layout manager.
53194 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
53195 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
53196 * @cfg {Boolean} floatable False to disable floating (defaults to true)
53197 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
53198 * @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})
53199 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
53200 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
53201 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
53202 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
53203 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
53204 * @cfg {String} title The title for the region (overrides panel titles)
53205 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
53206 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
53207 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
53208 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
53209 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
53210 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
53211 * the space available, similar to FireFox 1.5 tabs (defaults to false)
53212 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
53213 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
53214 * @cfg {Boolean} showPin True to show a pin button
53215 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
53216 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
53217 * @cfg {Boolean} disableTabTips True to disable tab tooltips
53218 * @cfg {Number} width For East/West panels
53219 * @cfg {Number} height For North/South panels
53220 * @cfg {Boolean} split To show the splitter
53221 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
53223 Roo.LayoutRegion = function(mgr, config, pos){
53224 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
53225 var dh = Roo.DomHelper;
53226 /** This region's container element
53227 * @type Roo.Element */
53228 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
53229 /** This region's title element
53230 * @type Roo.Element */
53232 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
53233 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
53234 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
53236 this.titleEl.enableDisplayMode();
53237 /** This region's title text element
53238 * @type HTMLElement */
53239 this.titleTextEl = this.titleEl.dom.firstChild;
53240 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
53241 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
53242 this.closeBtn.enableDisplayMode();
53243 this.closeBtn.on("click", this.closeClicked, this);
53244 this.closeBtn.hide();
53246 this.createBody(config);
53247 this.visible = true;
53248 this.collapsed = false;
53250 if(config.hideWhenEmpty){
53252 this.on("paneladded", this.validateVisibility, this);
53253 this.on("panelremoved", this.validateVisibility, this);
53255 this.applyConfig(config);
53258 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
53260 createBody : function(){
53261 /** This region's body element
53262 * @type Roo.Element */
53263 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
53266 applyConfig : function(c){
53267 if(c.collapsible && this.position != "center" && !this.collapsedEl){
53268 var dh = Roo.DomHelper;
53269 if(c.titlebar !== false){
53270 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
53271 this.collapseBtn.on("click", this.collapse, this);
53272 this.collapseBtn.enableDisplayMode();
53274 if(c.showPin === true || this.showPin){
53275 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
53276 this.stickBtn.enableDisplayMode();
53277 this.stickBtn.on("click", this.expand, this);
53278 this.stickBtn.hide();
53281 /** This region's collapsed element
53282 * @type Roo.Element */
53283 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
53284 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
53286 if(c.floatable !== false){
53287 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
53288 this.collapsedEl.on("click", this.collapseClick, this);
53291 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
53292 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
53293 id: "message", unselectable: "on", style:{"float":"left"}});
53294 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
53296 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
53297 this.expandBtn.on("click", this.expand, this);
53299 if(this.collapseBtn){
53300 this.collapseBtn.setVisible(c.collapsible == true);
53302 this.cmargins = c.cmargins || this.cmargins ||
53303 (this.position == "west" || this.position == "east" ?
53304 {top: 0, left: 2, right:2, bottom: 0} :
53305 {top: 2, left: 0, right:0, bottom: 2});
53306 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
53307 this.bottomTabs = c.tabPosition != "top";
53308 this.autoScroll = c.autoScroll || false;
53309 if(this.autoScroll){
53310 this.bodyEl.setStyle("overflow", "auto");
53312 this.bodyEl.setStyle("overflow", "hidden");
53314 //if(c.titlebar !== false){
53315 if((!c.titlebar && !c.title) || c.titlebar === false){
53316 this.titleEl.hide();
53318 this.titleEl.show();
53320 this.titleTextEl.innerHTML = c.title;
53324 this.duration = c.duration || .30;
53325 this.slideDuration = c.slideDuration || .45;
53328 this.collapse(true);
53335 * Returns true if this region is currently visible.
53336 * @return {Boolean}
53338 isVisible : function(){
53339 return this.visible;
53343 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
53344 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
53346 setCollapsedTitle : function(title){
53347 title = title || " ";
53348 if(this.collapsedTitleTextEl){
53349 this.collapsedTitleTextEl.innerHTML = title;
53353 getBox : function(){
53355 if(!this.collapsed){
53356 b = this.el.getBox(false, true);
53358 b = this.collapsedEl.getBox(false, true);
53363 getMargins : function(){
53364 return this.collapsed ? this.cmargins : this.margins;
53367 highlight : function(){
53368 this.el.addClass("x-layout-panel-dragover");
53371 unhighlight : function(){
53372 this.el.removeClass("x-layout-panel-dragover");
53375 updateBox : function(box){
53377 if(!this.collapsed){
53378 this.el.dom.style.left = box.x + "px";
53379 this.el.dom.style.top = box.y + "px";
53380 this.updateBody(box.width, box.height);
53382 this.collapsedEl.dom.style.left = box.x + "px";
53383 this.collapsedEl.dom.style.top = box.y + "px";
53384 this.collapsedEl.setSize(box.width, box.height);
53387 this.tabs.autoSizeTabs();
53391 updateBody : function(w, h){
53393 this.el.setWidth(w);
53394 w -= this.el.getBorderWidth("rl");
53395 if(this.config.adjustments){
53396 w += this.config.adjustments[0];
53400 this.el.setHeight(h);
53401 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
53402 h -= this.el.getBorderWidth("tb");
53403 if(this.config.adjustments){
53404 h += this.config.adjustments[1];
53406 this.bodyEl.setHeight(h);
53408 h = this.tabs.syncHeight(h);
53411 if(this.panelSize){
53412 w = w !== null ? w : this.panelSize.width;
53413 h = h !== null ? h : this.panelSize.height;
53415 if(this.activePanel){
53416 var el = this.activePanel.getEl();
53417 w = w !== null ? w : el.getWidth();
53418 h = h !== null ? h : el.getHeight();
53419 this.panelSize = {width: w, height: h};
53420 this.activePanel.setSize(w, h);
53422 if(Roo.isIE && this.tabs){
53423 this.tabs.el.repaint();
53428 * Returns the container element for this region.
53429 * @return {Roo.Element}
53431 getEl : function(){
53436 * Hides this region.
53439 if(!this.collapsed){
53440 this.el.dom.style.left = "-2000px";
53443 this.collapsedEl.dom.style.left = "-2000px";
53444 this.collapsedEl.hide();
53446 this.visible = false;
53447 this.fireEvent("visibilitychange", this, false);
53451 * Shows this region if it was previously hidden.
53454 if(!this.collapsed){
53457 this.collapsedEl.show();
53459 this.visible = true;
53460 this.fireEvent("visibilitychange", this, true);
53463 closeClicked : function(){
53464 if(this.activePanel){
53465 this.remove(this.activePanel);
53469 collapseClick : function(e){
53471 e.stopPropagation();
53474 e.stopPropagation();
53480 * Collapses this region.
53481 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
53483 collapse : function(skipAnim, skipCheck){
53484 if(this.collapsed) {
53488 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
53490 this.collapsed = true;
53492 this.split.el.hide();
53494 if(this.config.animate && skipAnim !== true){
53495 this.fireEvent("invalidated", this);
53496 this.animateCollapse();
53498 this.el.setLocation(-20000,-20000);
53500 this.collapsedEl.show();
53501 this.fireEvent("collapsed", this);
53502 this.fireEvent("invalidated", this);
53508 animateCollapse : function(){
53513 * Expands this region if it was previously collapsed.
53514 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
53515 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
53517 expand : function(e, skipAnim){
53519 e.stopPropagation();
53521 if(!this.collapsed || this.el.hasActiveFx()) {
53525 this.afterSlideIn();
53528 this.collapsed = false;
53529 if(this.config.animate && skipAnim !== true){
53530 this.animateExpand();
53534 this.split.el.show();
53536 this.collapsedEl.setLocation(-2000,-2000);
53537 this.collapsedEl.hide();
53538 this.fireEvent("invalidated", this);
53539 this.fireEvent("expanded", this);
53543 animateExpand : function(){
53547 initTabs : function()
53549 this.bodyEl.setStyle("overflow", "hidden");
53550 var ts = new Roo.TabPanel(
53553 tabPosition: this.bottomTabs ? 'bottom' : 'top',
53554 disableTooltips: this.config.disableTabTips,
53555 toolbar : this.config.toolbar
53558 if(this.config.hideTabs){
53559 ts.stripWrap.setDisplayed(false);
53562 ts.resizeTabs = this.config.resizeTabs === true;
53563 ts.minTabWidth = this.config.minTabWidth || 40;
53564 ts.maxTabWidth = this.config.maxTabWidth || 250;
53565 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
53566 ts.monitorResize = false;
53567 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
53568 ts.bodyEl.addClass('x-layout-tabs-body');
53569 this.panels.each(this.initPanelAsTab, this);
53572 initPanelAsTab : function(panel){
53573 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
53574 this.config.closeOnTab && panel.isClosable());
53575 if(panel.tabTip !== undefined){
53576 ti.setTooltip(panel.tabTip);
53578 ti.on("activate", function(){
53579 this.setActivePanel(panel);
53581 if(this.config.closeOnTab){
53582 ti.on("beforeclose", function(t, e){
53584 this.remove(panel);
53590 updatePanelTitle : function(panel, title){
53591 if(this.activePanel == panel){
53592 this.updateTitle(title);
53595 var ti = this.tabs.getTab(panel.getEl().id);
53597 if(panel.tabTip !== undefined){
53598 ti.setTooltip(panel.tabTip);
53603 updateTitle : function(title){
53604 if(this.titleTextEl && !this.config.title){
53605 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
53609 setActivePanel : function(panel){
53610 panel = this.getPanel(panel);
53611 if(this.activePanel && this.activePanel != panel){
53612 this.activePanel.setActiveState(false);
53614 this.activePanel = panel;
53615 panel.setActiveState(true);
53616 if(this.panelSize){
53617 panel.setSize(this.panelSize.width, this.panelSize.height);
53620 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
53622 this.updateTitle(panel.getTitle());
53624 this.fireEvent("invalidated", this);
53626 this.fireEvent("panelactivated", this, panel);
53630 * Shows the specified panel.
53631 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
53632 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
53634 showPanel : function(panel)
53636 panel = this.getPanel(panel);
53639 var tab = this.tabs.getTab(panel.getEl().id);
53640 if(tab.isHidden()){
53641 this.tabs.unhideTab(tab.id);
53645 this.setActivePanel(panel);
53652 * Get the active panel for this region.
53653 * @return {Roo.ContentPanel} The active panel or null
53655 getActivePanel : function(){
53656 return this.activePanel;
53659 validateVisibility : function(){
53660 if(this.panels.getCount() < 1){
53661 this.updateTitle(" ");
53662 this.closeBtn.hide();
53665 if(!this.isVisible()){
53672 * Adds the passed ContentPanel(s) to this region.
53673 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
53674 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
53676 add : function(panel){
53677 if(arguments.length > 1){
53678 for(var i = 0, len = arguments.length; i < len; i++) {
53679 this.add(arguments[i]);
53683 if(this.hasPanel(panel)){
53684 this.showPanel(panel);
53687 panel.setRegion(this);
53688 this.panels.add(panel);
53689 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
53690 this.bodyEl.dom.appendChild(panel.getEl().dom);
53691 if(panel.background !== true){
53692 this.setActivePanel(panel);
53694 this.fireEvent("paneladded", this, panel);
53700 this.initPanelAsTab(panel);
53702 if(panel.background !== true){
53703 this.tabs.activate(panel.getEl().id);
53705 this.fireEvent("paneladded", this, panel);
53710 * Hides the tab for the specified panel.
53711 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
53713 hidePanel : function(panel){
53714 if(this.tabs && (panel = this.getPanel(panel))){
53715 this.tabs.hideTab(panel.getEl().id);
53720 * Unhides the tab for a previously hidden panel.
53721 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
53723 unhidePanel : function(panel){
53724 if(this.tabs && (panel = this.getPanel(panel))){
53725 this.tabs.unhideTab(panel.getEl().id);
53729 clearPanels : function(){
53730 while(this.panels.getCount() > 0){
53731 this.remove(this.panels.first());
53736 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
53737 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
53738 * @param {Boolean} preservePanel Overrides the config preservePanel option
53739 * @return {Roo.ContentPanel} The panel that was removed
53741 remove : function(panel, preservePanel){
53742 panel = this.getPanel(panel);
53747 this.fireEvent("beforeremove", this, panel, e);
53748 if(e.cancel === true){
53751 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
53752 var panelId = panel.getId();
53753 this.panels.removeKey(panelId);
53755 document.body.appendChild(panel.getEl().dom);
53758 this.tabs.removeTab(panel.getEl().id);
53759 }else if (!preservePanel){
53760 this.bodyEl.dom.removeChild(panel.getEl().dom);
53762 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
53763 var p = this.panels.first();
53764 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
53765 tempEl.appendChild(p.getEl().dom);
53766 this.bodyEl.update("");
53767 this.bodyEl.dom.appendChild(p.getEl().dom);
53769 this.updateTitle(p.getTitle());
53771 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
53772 this.setActivePanel(p);
53774 panel.setRegion(null);
53775 if(this.activePanel == panel){
53776 this.activePanel = null;
53778 if(this.config.autoDestroy !== false && preservePanel !== true){
53779 try{panel.destroy();}catch(e){}
53781 this.fireEvent("panelremoved", this, panel);
53786 * Returns the TabPanel component used by this region
53787 * @return {Roo.TabPanel}
53789 getTabs : function(){
53793 createTool : function(parentEl, className){
53794 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
53795 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
53796 btn.addClassOnOver("x-layout-tools-button-over");
53801 * Ext JS Library 1.1.1
53802 * Copyright(c) 2006-2007, Ext JS, LLC.
53804 * Originally Released Under LGPL - original licence link has changed is not relivant.
53807 * <script type="text/javascript">
53813 * @class Roo.SplitLayoutRegion
53814 * @extends Roo.LayoutRegion
53815 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
53817 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
53818 this.cursor = cursor;
53819 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
53822 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
53823 splitTip : "Drag to resize.",
53824 collapsibleSplitTip : "Drag to resize. Double click to hide.",
53825 useSplitTips : false,
53827 applyConfig : function(config){
53828 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
53831 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
53832 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
53833 /** The SplitBar for this region
53834 * @type Roo.SplitBar */
53835 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
53836 this.split.on("moved", this.onSplitMove, this);
53837 this.split.useShim = config.useShim === true;
53838 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
53839 if(this.useSplitTips){
53840 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
53842 if(config.collapsible){
53843 this.split.el.on("dblclick", this.collapse, this);
53846 if(typeof config.minSize != "undefined"){
53847 this.split.minSize = config.minSize;
53849 if(typeof config.maxSize != "undefined"){
53850 this.split.maxSize = config.maxSize;
53852 if(config.hideWhenEmpty || config.hidden || config.collapsed){
53853 this.hideSplitter();
53858 getHMaxSize : function(){
53859 var cmax = this.config.maxSize || 10000;
53860 var center = this.mgr.getRegion("center");
53861 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
53864 getVMaxSize : function(){
53865 var cmax = this.config.maxSize || 10000;
53866 var center = this.mgr.getRegion("center");
53867 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
53870 onSplitMove : function(split, newSize){
53871 this.fireEvent("resized", this, newSize);
53875 * Returns the {@link Roo.SplitBar} for this region.
53876 * @return {Roo.SplitBar}
53878 getSplitBar : function(){
53883 this.hideSplitter();
53884 Roo.SplitLayoutRegion.superclass.hide.call(this);
53887 hideSplitter : function(){
53889 this.split.el.setLocation(-2000,-2000);
53890 this.split.el.hide();
53896 this.split.el.show();
53898 Roo.SplitLayoutRegion.superclass.show.call(this);
53901 beforeSlide: function(){
53902 if(Roo.isGecko){// firefox overflow auto bug workaround
53903 this.bodyEl.clip();
53905 this.tabs.bodyEl.clip();
53907 if(this.activePanel){
53908 this.activePanel.getEl().clip();
53910 if(this.activePanel.beforeSlide){
53911 this.activePanel.beforeSlide();
53917 afterSlide : function(){
53918 if(Roo.isGecko){// firefox overflow auto bug workaround
53919 this.bodyEl.unclip();
53921 this.tabs.bodyEl.unclip();
53923 if(this.activePanel){
53924 this.activePanel.getEl().unclip();
53925 if(this.activePanel.afterSlide){
53926 this.activePanel.afterSlide();
53932 initAutoHide : function(){
53933 if(this.autoHide !== false){
53934 if(!this.autoHideHd){
53935 var st = new Roo.util.DelayedTask(this.slideIn, this);
53936 this.autoHideHd = {
53937 "mouseout": function(e){
53938 if(!e.within(this.el, true)){
53942 "mouseover" : function(e){
53948 this.el.on(this.autoHideHd);
53952 clearAutoHide : function(){
53953 if(this.autoHide !== false){
53954 this.el.un("mouseout", this.autoHideHd.mouseout);
53955 this.el.un("mouseover", this.autoHideHd.mouseover);
53959 clearMonitor : function(){
53960 Roo.get(document).un("click", this.slideInIf, this);
53963 // these names are backwards but not changed for compat
53964 slideOut : function(){
53965 if(this.isSlid || this.el.hasActiveFx()){
53968 this.isSlid = true;
53969 if(this.collapseBtn){
53970 this.collapseBtn.hide();
53972 this.closeBtnState = this.closeBtn.getStyle('display');
53973 this.closeBtn.hide();
53975 this.stickBtn.show();
53978 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
53979 this.beforeSlide();
53980 this.el.setStyle("z-index", 10001);
53981 this.el.slideIn(this.getSlideAnchor(), {
53982 callback: function(){
53984 this.initAutoHide();
53985 Roo.get(document).on("click", this.slideInIf, this);
53986 this.fireEvent("slideshow", this);
53993 afterSlideIn : function(){
53994 this.clearAutoHide();
53995 this.isSlid = false;
53996 this.clearMonitor();
53997 this.el.setStyle("z-index", "");
53998 if(this.collapseBtn){
53999 this.collapseBtn.show();
54001 this.closeBtn.setStyle('display', this.closeBtnState);
54003 this.stickBtn.hide();
54005 this.fireEvent("slidehide", this);
54008 slideIn : function(cb){
54009 if(!this.isSlid || this.el.hasActiveFx()){
54013 this.isSlid = false;
54014 this.beforeSlide();
54015 this.el.slideOut(this.getSlideAnchor(), {
54016 callback: function(){
54017 this.el.setLeftTop(-10000, -10000);
54019 this.afterSlideIn();
54027 slideInIf : function(e){
54028 if(!e.within(this.el)){
54033 animateCollapse : function(){
54034 this.beforeSlide();
54035 this.el.setStyle("z-index", 20000);
54036 var anchor = this.getSlideAnchor();
54037 this.el.slideOut(anchor, {
54038 callback : function(){
54039 this.el.setStyle("z-index", "");
54040 this.collapsedEl.slideIn(anchor, {duration:.3});
54042 this.el.setLocation(-10000,-10000);
54044 this.fireEvent("collapsed", this);
54051 animateExpand : function(){
54052 this.beforeSlide();
54053 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
54054 this.el.setStyle("z-index", 20000);
54055 this.collapsedEl.hide({
54058 this.el.slideIn(this.getSlideAnchor(), {
54059 callback : function(){
54060 this.el.setStyle("z-index", "");
54063 this.split.el.show();
54065 this.fireEvent("invalidated", this);
54066 this.fireEvent("expanded", this);
54094 getAnchor : function(){
54095 return this.anchors[this.position];
54098 getCollapseAnchor : function(){
54099 return this.canchors[this.position];
54102 getSlideAnchor : function(){
54103 return this.sanchors[this.position];
54106 getAlignAdj : function(){
54107 var cm = this.cmargins;
54108 switch(this.position){
54124 getExpandAdj : function(){
54125 var c = this.collapsedEl, cm = this.cmargins;
54126 switch(this.position){
54128 return [-(cm.right+c.getWidth()+cm.left), 0];
54131 return [cm.right+c.getWidth()+cm.left, 0];
54134 return [0, -(cm.top+cm.bottom+c.getHeight())];
54137 return [0, cm.top+cm.bottom+c.getHeight()];
54143 * Ext JS Library 1.1.1
54144 * Copyright(c) 2006-2007, Ext JS, LLC.
54146 * Originally Released Under LGPL - original licence link has changed is not relivant.
54149 * <script type="text/javascript">
54152 * These classes are private internal classes
54154 Roo.CenterLayoutRegion = function(mgr, config){
54155 Roo.LayoutRegion.call(this, mgr, config, "center");
54156 this.visible = true;
54157 this.minWidth = config.minWidth || 20;
54158 this.minHeight = config.minHeight || 20;
54161 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
54163 // center panel can't be hidden
54167 // center panel can't be hidden
54170 getMinWidth: function(){
54171 return this.minWidth;
54174 getMinHeight: function(){
54175 return this.minHeight;
54180 Roo.NorthLayoutRegion = function(mgr, config){
54181 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
54183 this.split.placement = Roo.SplitBar.TOP;
54184 this.split.orientation = Roo.SplitBar.VERTICAL;
54185 this.split.el.addClass("x-layout-split-v");
54187 var size = config.initialSize || config.height;
54188 if(typeof size != "undefined"){
54189 this.el.setHeight(size);
54192 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
54193 orientation: Roo.SplitBar.VERTICAL,
54194 getBox : function(){
54195 if(this.collapsed){
54196 return this.collapsedEl.getBox();
54198 var box = this.el.getBox();
54200 box.height += this.split.el.getHeight();
54205 updateBox : function(box){
54206 if(this.split && !this.collapsed){
54207 box.height -= this.split.el.getHeight();
54208 this.split.el.setLeft(box.x);
54209 this.split.el.setTop(box.y+box.height);
54210 this.split.el.setWidth(box.width);
54212 if(this.collapsed){
54213 this.updateBody(box.width, null);
54215 Roo.LayoutRegion.prototype.updateBox.call(this, box);
54219 Roo.SouthLayoutRegion = function(mgr, config){
54220 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
54222 this.split.placement = Roo.SplitBar.BOTTOM;
54223 this.split.orientation = Roo.SplitBar.VERTICAL;
54224 this.split.el.addClass("x-layout-split-v");
54226 var size = config.initialSize || config.height;
54227 if(typeof size != "undefined"){
54228 this.el.setHeight(size);
54231 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
54232 orientation: Roo.SplitBar.VERTICAL,
54233 getBox : function(){
54234 if(this.collapsed){
54235 return this.collapsedEl.getBox();
54237 var box = this.el.getBox();
54239 var sh = this.split.el.getHeight();
54246 updateBox : function(box){
54247 if(this.split && !this.collapsed){
54248 var sh = this.split.el.getHeight();
54251 this.split.el.setLeft(box.x);
54252 this.split.el.setTop(box.y-sh);
54253 this.split.el.setWidth(box.width);
54255 if(this.collapsed){
54256 this.updateBody(box.width, null);
54258 Roo.LayoutRegion.prototype.updateBox.call(this, box);
54262 Roo.EastLayoutRegion = function(mgr, config){
54263 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
54265 this.split.placement = Roo.SplitBar.RIGHT;
54266 this.split.orientation = Roo.SplitBar.HORIZONTAL;
54267 this.split.el.addClass("x-layout-split-h");
54269 var size = config.initialSize || config.width;
54270 if(typeof size != "undefined"){
54271 this.el.setWidth(size);
54274 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
54275 orientation: Roo.SplitBar.HORIZONTAL,
54276 getBox : function(){
54277 if(this.collapsed){
54278 return this.collapsedEl.getBox();
54280 var box = this.el.getBox();
54282 var sw = this.split.el.getWidth();
54289 updateBox : function(box){
54290 if(this.split && !this.collapsed){
54291 var sw = this.split.el.getWidth();
54293 this.split.el.setLeft(box.x);
54294 this.split.el.setTop(box.y);
54295 this.split.el.setHeight(box.height);
54298 if(this.collapsed){
54299 this.updateBody(null, box.height);
54301 Roo.LayoutRegion.prototype.updateBox.call(this, box);
54305 Roo.WestLayoutRegion = function(mgr, config){
54306 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
54308 this.split.placement = Roo.SplitBar.LEFT;
54309 this.split.orientation = Roo.SplitBar.HORIZONTAL;
54310 this.split.el.addClass("x-layout-split-h");
54312 var size = config.initialSize || config.width;
54313 if(typeof size != "undefined"){
54314 this.el.setWidth(size);
54317 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
54318 orientation: Roo.SplitBar.HORIZONTAL,
54319 getBox : function(){
54320 if(this.collapsed){
54321 return this.collapsedEl.getBox();
54323 var box = this.el.getBox();
54325 box.width += this.split.el.getWidth();
54330 updateBox : function(box){
54331 if(this.split && !this.collapsed){
54332 var sw = this.split.el.getWidth();
54334 this.split.el.setLeft(box.x+box.width);
54335 this.split.el.setTop(box.y);
54336 this.split.el.setHeight(box.height);
54338 if(this.collapsed){
54339 this.updateBody(null, box.height);
54341 Roo.LayoutRegion.prototype.updateBox.call(this, box);
54346 * Ext JS Library 1.1.1
54347 * Copyright(c) 2006-2007, Ext JS, LLC.
54349 * Originally Released Under LGPL - original licence link has changed is not relivant.
54352 * <script type="text/javascript">
54357 * Private internal class for reading and applying state
54359 Roo.LayoutStateManager = function(layout){
54360 // default empty state
54369 Roo.LayoutStateManager.prototype = {
54370 init : function(layout, provider){
54371 this.provider = provider;
54372 var state = provider.get(layout.id+"-layout-state");
54374 var wasUpdating = layout.isUpdating();
54376 layout.beginUpdate();
54378 for(var key in state){
54379 if(typeof state[key] != "function"){
54380 var rstate = state[key];
54381 var r = layout.getRegion(key);
54384 r.resizeTo(rstate.size);
54386 if(rstate.collapsed == true){
54389 r.expand(null, true);
54395 layout.endUpdate();
54397 this.state = state;
54399 this.layout = layout;
54400 layout.on("regionresized", this.onRegionResized, this);
54401 layout.on("regioncollapsed", this.onRegionCollapsed, this);
54402 layout.on("regionexpanded", this.onRegionExpanded, this);
54405 storeState : function(){
54406 this.provider.set(this.layout.id+"-layout-state", this.state);
54409 onRegionResized : function(region, newSize){
54410 this.state[region.getPosition()].size = newSize;
54414 onRegionCollapsed : function(region){
54415 this.state[region.getPosition()].collapsed = true;
54419 onRegionExpanded : function(region){
54420 this.state[region.getPosition()].collapsed = false;
54425 * Ext JS Library 1.1.1
54426 * Copyright(c) 2006-2007, Ext JS, LLC.
54428 * Originally Released Under LGPL - original licence link has changed is not relivant.
54431 * <script type="text/javascript">
54434 * @class Roo.ContentPanel
54435 * @extends Roo.util.Observable
54436 * @children Roo.form.Form Roo.JsonView Roo.View
54438 * A basic ContentPanel element.
54439 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
54440 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
54441 * @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
54442 * @cfg {Boolean} closable True if the panel can be closed/removed
54443 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
54444 * @cfg {String|HTMLElement|Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
54445 * @cfg {Roo.Toolbar} toolbar A toolbar for this panel
54446 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
54447 * @cfg {String} title The title for this panel
54448 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
54449 * @cfg {String} url Calls {@link #setUrl} with this value
54450 * @cfg {String} region [required] (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
54451 * @cfg {String|Object} params When used with {@link #url}, calls {@link #setUrl} with this value
54452 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
54453 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
54454 * @cfg {String} style Extra style to add to the content panel
54455 * @cfg {Roo.menu.Menu} menu popup menu
54458 * Create a new ContentPanel.
54459 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
54460 * @param {String/Object} config A string to set only the title or a config object
54461 * @param {String} content (optional) Set the HTML content for this panel
54462 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
54464 Roo.ContentPanel = function(el, config, content){
54468 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
54472 if (config && config.parentLayout) {
54473 el = config.parentLayout.el.createChild();
54476 if(el.autoCreate){ // xtype is available if this is called from factory
54480 this.el = Roo.get(el);
54481 if(!this.el && config && config.autoCreate){
54482 if(typeof config.autoCreate == "object"){
54483 if(!config.autoCreate.id){
54484 config.autoCreate.id = config.id||el;
54486 this.el = Roo.DomHelper.append(document.body,
54487 config.autoCreate, true);
54489 this.el = Roo.DomHelper.append(document.body,
54490 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
54495 this.closable = false;
54496 this.loaded = false;
54497 this.active = false;
54498 if(typeof config == "string"){
54499 this.title = config;
54501 Roo.apply(this, config);
54504 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
54505 this.wrapEl = this.el.wrap();
54506 this.toolbar.container = this.el.insertSibling(false, 'before');
54507 this.toolbar = new Roo.Toolbar(this.toolbar);
54510 // xtype created footer. - not sure if will work as we normally have to render first..
54511 if (this.footer && !this.footer.el && this.footer.xtype) {
54512 if (!this.wrapEl) {
54513 this.wrapEl = this.el.wrap();
54516 this.footer.container = this.wrapEl.createChild();
54518 this.footer = Roo.factory(this.footer, Roo);
54523 this.resizeEl = Roo.get(this.resizeEl, true);
54525 this.resizeEl = this.el;
54527 // handle view.xtype
54535 * Fires when this panel is activated.
54536 * @param {Roo.ContentPanel} this
54540 * @event deactivate
54541 * Fires when this panel is activated.
54542 * @param {Roo.ContentPanel} this
54544 "deactivate" : true,
54548 * Fires when this panel is resized if fitToFrame is true.
54549 * @param {Roo.ContentPanel} this
54550 * @param {Number} width The width after any component adjustments
54551 * @param {Number} height The height after any component adjustments
54557 * Fires when this tab is created
54558 * @param {Roo.ContentPanel} this
54568 if(this.autoScroll){
54569 this.resizeEl.setStyle("overflow", "auto");
54571 // fix randome scrolling
54572 this.el.on('scroll', function() {
54573 Roo.log('fix random scolling');
54574 this.scrollTo('top',0);
54577 content = content || this.content;
54579 this.setContent(content);
54581 if(config && config.url){
54582 this.setUrl(this.url, this.params, this.loadOnce);
54587 Roo.ContentPanel.superclass.constructor.call(this);
54589 if (this.view && typeof(this.view.xtype) != 'undefined') {
54590 this.view.el = this.el.appendChild(document.createElement("div"));
54591 this.view = Roo.factory(this.view);
54592 this.view.render && this.view.render(false, '');
54596 this.fireEvent('render', this);
54599 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
54601 setRegion : function(region){
54602 this.region = region;
54604 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
54606 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
54611 * Returns the toolbar for this Panel if one was configured.
54612 * @return {Roo.Toolbar}
54614 getToolbar : function(){
54615 return this.toolbar;
54618 setActiveState : function(active){
54619 this.active = active;
54621 this.fireEvent("deactivate", this);
54623 this.fireEvent("activate", this);
54627 * Updates this panel's element
54628 * @param {String} content The new content
54629 * @param {Boolean} loadScripts (optional) true to look for and process scripts
54631 setContent : function(content, loadScripts){
54632 this.el.update(content, loadScripts);
54635 ignoreResize : function(w, h){
54636 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
54639 this.lastSize = {width: w, height: h};
54644 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
54645 * @return {Roo.UpdateManager} The UpdateManager
54647 getUpdateManager : function(){
54648 return this.el.getUpdateManager();
54651 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
54652 * @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:
54655 url: "your-url.php",
54656 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
54657 callback: yourFunction,
54658 scope: yourObject, //(optional scope)
54661 text: "Loading...",
54666 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
54667 * 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.
54668 * @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}
54669 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
54670 * @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.
54671 * @return {Roo.ContentPanel} this
54674 var um = this.el.getUpdateManager();
54675 um.update.apply(um, arguments);
54681 * 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.
54682 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
54683 * @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)
54684 * @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)
54685 * @return {Roo.UpdateManager} The UpdateManager
54687 setUrl : function(url, params, loadOnce){
54688 if(this.refreshDelegate){
54689 this.removeListener("activate", this.refreshDelegate);
54691 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
54692 this.on("activate", this.refreshDelegate);
54693 return this.el.getUpdateManager();
54696 _handleRefresh : function(url, params, loadOnce){
54697 if(!loadOnce || !this.loaded){
54698 var updater = this.el.getUpdateManager();
54699 updater.update(url, params, this._setLoaded.createDelegate(this));
54703 _setLoaded : function(){
54704 this.loaded = true;
54708 * Returns this panel's id
54711 getId : function(){
54716 * Returns this panel's element - used by regiosn to add.
54717 * @return {Roo.Element}
54719 getEl : function(){
54720 return this.wrapEl || this.el;
54723 adjustForComponents : function(width, height)
54725 //Roo.log('adjustForComponents ');
54726 if(this.resizeEl != this.el){
54727 width -= this.el.getFrameWidth('lr');
54728 height -= this.el.getFrameWidth('tb');
54731 var te = this.toolbar.getEl();
54732 height -= te.getHeight();
54733 te.setWidth(width);
54736 var te = this.footer.getEl();
54737 //Roo.log("footer:" + te.getHeight());
54739 height -= te.getHeight();
54740 te.setWidth(width);
54744 if(this.adjustments){
54745 width += this.adjustments[0];
54746 height += this.adjustments[1];
54748 return {"width": width, "height": height};
54751 setSize : function(width, height){
54752 if(this.fitToFrame && !this.ignoreResize(width, height)){
54753 if(this.fitContainer && this.resizeEl != this.el){
54754 this.el.setSize(width, height);
54756 var size = this.adjustForComponents(width, height);
54757 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
54758 this.fireEvent('resize', this, size.width, size.height);
54763 * Returns this panel's title
54766 getTitle : function(){
54771 * Set this panel's title
54772 * @param {String} title
54774 setTitle : function(title){
54775 this.title = title;
54777 this.region.updatePanelTitle(this, title);
54782 * Returns true is this panel was configured to be closable
54783 * @return {Boolean}
54785 isClosable : function(){
54786 return this.closable;
54789 beforeSlide : function(){
54791 this.resizeEl.clip();
54794 afterSlide : function(){
54796 this.resizeEl.unclip();
54800 * Force a content refresh from the URL specified in the {@link #setUrl} method.
54801 * Will fail silently if the {@link #setUrl} method has not been called.
54802 * This does not activate the panel, just updates its content.
54804 refresh : function(){
54805 if(this.refreshDelegate){
54806 this.loaded = false;
54807 this.refreshDelegate();
54812 * Destroys this panel
54814 destroy : function(){
54815 this.el.removeAllListeners();
54816 var tempEl = document.createElement("span");
54817 tempEl.appendChild(this.el.dom);
54818 tempEl.innerHTML = "";
54824 * form - if the content panel contains a form - this is a reference to it.
54825 * @type {Roo.form.Form}
54829 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
54830 * This contains a reference to it.
54836 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
54846 * @param {Object} cfg Xtype definition of item to add.
54849 addxtype : function(cfg) {
54851 if (cfg.xtype.match(/^Form$/)) {
54854 //if (this.footer) {
54855 // el = this.footer.container.insertSibling(false, 'before');
54857 el = this.el.createChild();
54860 this.form = new Roo.form.Form(cfg);
54863 if ( this.form.allItems.length) {
54864 this.form.render(el.dom);
54868 // should only have one of theses..
54869 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
54870 // views.. should not be just added - used named prop 'view''
54872 cfg.el = this.el.appendChild(document.createElement("div"));
54875 var ret = new Roo.factory(cfg);
54877 ret.render && ret.render(false, ''); // render blank..
54886 * @class Roo.GridPanel
54887 * @extends Roo.ContentPanel
54889 * Create a new GridPanel.
54890 * @param {Roo.grid.Grid} grid The grid for this panel
54891 * @param {String/Object} config A string to set only the panel's title, or a config object
54893 Roo.GridPanel = function(grid, config){
54896 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
54897 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
54899 this.wrapper.dom.appendChild(grid.getGridEl().dom);
54901 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
54904 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
54906 // xtype created footer. - not sure if will work as we normally have to render first..
54907 if (this.footer && !this.footer.el && this.footer.xtype) {
54909 this.footer.container = this.grid.getView().getFooterPanel(true);
54910 this.footer.dataSource = this.grid.dataSource;
54911 this.footer = Roo.factory(this.footer, Roo);
54915 grid.monitorWindowResize = false; // turn off autosizing
54916 grid.autoHeight = false;
54917 grid.autoWidth = false;
54919 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
54922 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
54923 getId : function(){
54924 return this.grid.id;
54928 * Returns the grid for this panel
54929 * @return {Roo.grid.Grid}
54931 getGrid : function(){
54935 setSize : function(width, height){
54936 if(!this.ignoreResize(width, height)){
54937 var grid = this.grid;
54938 var size = this.adjustForComponents(width, height);
54939 grid.getGridEl().setSize(size.width, size.height);
54944 beforeSlide : function(){
54945 this.grid.getView().scroller.clip();
54948 afterSlide : function(){
54949 this.grid.getView().scroller.unclip();
54952 destroy : function(){
54953 this.grid.destroy();
54955 Roo.GridPanel.superclass.destroy.call(this);
54961 * @class Roo.NestedLayoutPanel
54962 * @extends Roo.ContentPanel
54964 * Create a new NestedLayoutPanel.
54967 * @param {Roo.BorderLayout} layout [required] The layout for this panel
54968 * @param {String/Object} config A string to set only the title or a config object
54970 Roo.NestedLayoutPanel = function(layout, config)
54972 // construct with only one argument..
54973 /* FIXME - implement nicer consturctors
54974 if (layout.layout) {
54976 layout = config.layout;
54977 delete config.layout;
54979 if (layout.xtype && !layout.getEl) {
54980 // then layout needs constructing..
54981 layout = Roo.factory(layout, Roo);
54986 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
54988 layout.monitorWindowResize = false; // turn off autosizing
54989 this.layout = layout;
54990 this.layout.getEl().addClass("x-layout-nested-layout");
54997 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
54999 setSize : function(width, height){
55000 if(!this.ignoreResize(width, height)){
55001 var size = this.adjustForComponents(width, height);
55002 var el = this.layout.getEl();
55003 el.setSize(size.width, size.height);
55004 var touch = el.dom.offsetWidth;
55005 this.layout.layout();
55006 // ie requires a double layout on the first pass
55007 if(Roo.isIE && !this.initialized){
55008 this.initialized = true;
55009 this.layout.layout();
55014 // activate all subpanels if not currently active..
55016 setActiveState : function(active){
55017 this.active = active;
55019 this.fireEvent("deactivate", this);
55023 this.fireEvent("activate", this);
55024 // not sure if this should happen before or after..
55025 if (!this.layout) {
55026 return; // should not happen..
55029 for (var r in this.layout.regions) {
55030 reg = this.layout.getRegion(r);
55031 if (reg.getActivePanel()) {
55032 //reg.showPanel(reg.getActivePanel()); // force it to activate..
55033 reg.setActivePanel(reg.getActivePanel());
55036 if (!reg.panels.length) {
55039 reg.showPanel(reg.getPanel(0));
55048 * Returns the nested BorderLayout for this panel
55049 * @return {Roo.BorderLayout}
55051 getLayout : function(){
55052 return this.layout;
55056 * Adds a xtype elements to the layout of the nested panel
55060 xtype : 'ContentPanel',
55067 xtype : 'NestedLayoutPanel',
55073 items : [ ... list of content panels or nested layout panels.. ]
55077 * @param {Object} cfg Xtype definition of item to add.
55079 addxtype : function(cfg) {
55080 return this.layout.addxtype(cfg);
55085 Roo.ScrollPanel = function(el, config, content){
55086 config = config || {};
55087 config.fitToFrame = true;
55088 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
55090 this.el.dom.style.overflow = "hidden";
55091 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
55092 this.el.removeClass("x-layout-inactive-content");
55093 this.el.on("mousewheel", this.onWheel, this);
55095 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
55096 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
55097 up.unselectable(); down.unselectable();
55098 up.on("click", this.scrollUp, this);
55099 down.on("click", this.scrollDown, this);
55100 up.addClassOnOver("x-scroller-btn-over");
55101 down.addClassOnOver("x-scroller-btn-over");
55102 up.addClassOnClick("x-scroller-btn-click");
55103 down.addClassOnClick("x-scroller-btn-click");
55104 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
55106 this.resizeEl = this.el;
55107 this.el = wrap; this.up = up; this.down = down;
55110 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
55112 wheelIncrement : 5,
55113 scrollUp : function(){
55114 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
55117 scrollDown : function(){
55118 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
55121 afterScroll : function(){
55122 var el = this.resizeEl;
55123 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
55124 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
55125 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
55128 setSize : function(){
55129 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
55130 this.afterScroll();
55133 onWheel : function(e){
55134 var d = e.getWheelDelta();
55135 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
55136 this.afterScroll();
55140 setContent : function(content, loadScripts){
55141 this.resizeEl.update(content, loadScripts);
55149 * @class Roo.TreePanel
55150 * @extends Roo.ContentPanel
55151 * Treepanel component
55154 * Create a new TreePanel. - defaults to fit/scoll contents.
55155 * @param {String/Object} config A string to set only the panel's title, or a config object
55157 Roo.TreePanel = function(config){
55158 var el = config.el;
55159 var tree = config.tree;
55160 delete config.tree;
55161 delete config.el; // hopefull!
55163 // wrapper for IE7 strict & safari scroll issue
55165 var treeEl = el.createChild();
55166 config.resizeEl = treeEl;
55170 Roo.TreePanel.superclass.constructor.call(this, el, config);
55173 this.tree = new Roo.tree.TreePanel(treeEl , tree);
55174 //console.log(tree);
55175 this.on('activate', function()
55177 if (this.tree.rendered) {
55180 //console.log('render tree');
55181 this.tree.render();
55183 // this should not be needed.. - it's actually the 'el' that resizes?
55184 // actuall it breaks the containerScroll - dragging nodes auto scroll at top
55186 //this.on('resize', function (cp, w, h) {
55187 // this.tree.innerCt.setWidth(w);
55188 // this.tree.innerCt.setHeight(h);
55189 // //this.tree.innerCt.setStyle('overflow-y', 'auto');
55196 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
55200 * @cfg {Roo.tree.TreePanel} tree [required] The tree TreePanel, with config etc.
55218 * Ext JS Library 1.1.1
55219 * Copyright(c) 2006-2007, Ext JS, LLC.
55221 * Originally Released Under LGPL - original licence link has changed is not relivant.
55224 * <script type="text/javascript">
55229 * @class Roo.ReaderLayout
55230 * @extends Roo.BorderLayout
55231 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
55232 * center region containing two nested regions (a top one for a list view and one for item preview below),
55233 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
55234 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
55235 * expedites the setup of the overall layout and regions for this common application style.
55238 var reader = new Roo.ReaderLayout();
55239 var CP = Roo.ContentPanel; // shortcut for adding
55241 reader.beginUpdate();
55242 reader.add("north", new CP("north", "North"));
55243 reader.add("west", new CP("west", {title: "West"}));
55244 reader.add("east", new CP("east", {title: "East"}));
55246 reader.regions.listView.add(new CP("listView", "List"));
55247 reader.regions.preview.add(new CP("preview", "Preview"));
55248 reader.endUpdate();
55251 * Create a new ReaderLayout
55252 * @param {Object} config Configuration options
55253 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
55254 * document.body if omitted)
55256 Roo.ReaderLayout = function(config, renderTo){
55257 var c = config || {size:{}};
55258 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
55259 north: c.north !== false ? Roo.apply({
55263 }, c.north) : false,
55264 west: c.west !== false ? Roo.apply({
55272 margins:{left:5,right:0,bottom:5,top:5},
55273 cmargins:{left:5,right:5,bottom:5,top:5}
55274 }, c.west) : false,
55275 east: c.east !== false ? Roo.apply({
55283 margins:{left:0,right:5,bottom:5,top:5},
55284 cmargins:{left:5,right:5,bottom:5,top:5}
55285 }, c.east) : false,
55286 center: Roo.apply({
55287 tabPosition: 'top',
55291 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
55295 this.el.addClass('x-reader');
55297 this.beginUpdate();
55299 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
55300 south: c.preview !== false ? Roo.apply({
55307 cmargins:{top:5,left:0, right:0, bottom:0}
55308 }, c.preview) : false,
55309 center: Roo.apply({
55315 this.add('center', new Roo.NestedLayoutPanel(inner,
55316 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
55320 this.regions.preview = inner.getRegion('south');
55321 this.regions.listView = inner.getRegion('center');
55324 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
55326 * Ext JS Library 1.1.1
55327 * Copyright(c) 2006-2007, Ext JS, LLC.
55329 * Originally Released Under LGPL - original licence link has changed is not relivant.
55332 * <script type="text/javascript">
55336 * @class Roo.grid.Grid
55337 * @extends Roo.util.Observable
55338 * This class represents the primary interface of a component based grid control.
55339 * <br><br>Usage:<pre><code>
55340 var grid = new Roo.grid.Grid("my-container-id", {
55343 selModel: mySelectionModel,
55344 autoSizeColumns: true,
55345 monitorWindowResize: false,
55346 trackMouseOver: true
55351 * <b>Common Problems:</b><br/>
55352 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
55353 * element will correct this<br/>
55354 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
55355 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
55356 * are unpredictable.<br/>
55357 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
55358 * grid to calculate dimensions/offsets.<br/>
55360 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
55361 * The container MUST have some type of size defined for the grid to fill. The container will be
55362 * automatically set to position relative if it isn't already.
55363 * @param {Object} config A config object that sets properties on this grid.
55365 Roo.grid.Grid = function(container, config){
55366 // initialize the container
55367 this.container = Roo.get(container);
55368 this.container.update("");
55369 this.container.setStyle("overflow", "hidden");
55370 this.container.addClass('x-grid-container');
55372 this.id = this.container.id;
55374 Roo.apply(this, config);
55375 // check and correct shorthanded configs
55377 this.dataSource = this.ds;
55381 this.colModel = this.cm;
55385 this.selModel = this.sm;
55389 if (this.selModel) {
55390 this.selModel = Roo.factory(this.selModel, Roo.grid);
55391 this.sm = this.selModel;
55392 this.sm.xmodule = this.xmodule || false;
55394 if (typeof(this.colModel.config) == 'undefined') {
55395 this.colModel = new Roo.grid.ColumnModel(this.colModel);
55396 this.cm = this.colModel;
55397 this.cm.xmodule = this.xmodule || false;
55399 if (this.dataSource) {
55400 this.dataSource= Roo.factory(this.dataSource, Roo.data);
55401 this.ds = this.dataSource;
55402 this.ds.xmodule = this.xmodule || false;
55409 this.container.setWidth(this.width);
55413 this.container.setHeight(this.height);
55420 * The raw click event for the entire grid.
55421 * @param {Roo.EventObject} e
55426 * The raw dblclick event for the entire grid.
55427 * @param {Roo.EventObject} e
55431 * @event contextmenu
55432 * The raw contextmenu event for the entire grid.
55433 * @param {Roo.EventObject} e
55435 "contextmenu" : true,
55438 * The raw mousedown event for the entire grid.
55439 * @param {Roo.EventObject} e
55441 "mousedown" : true,
55444 * The raw mouseup event for the entire grid.
55445 * @param {Roo.EventObject} e
55450 * The raw mouseover event for the entire grid.
55451 * @param {Roo.EventObject} e
55453 "mouseover" : true,
55456 * The raw mouseout event for the entire grid.
55457 * @param {Roo.EventObject} e
55462 * The raw keypress event for the entire grid.
55463 * @param {Roo.EventObject} e
55468 * The raw keydown event for the entire grid.
55469 * @param {Roo.EventObject} e
55477 * Fires when a cell is clicked
55478 * @param {Grid} this
55479 * @param {Number} rowIndex
55480 * @param {Number} columnIndex
55481 * @param {Roo.EventObject} e
55483 "cellclick" : true,
55485 * @event celldblclick
55486 * Fires when a cell is double clicked
55487 * @param {Grid} this
55488 * @param {Number} rowIndex
55489 * @param {Number} columnIndex
55490 * @param {Roo.EventObject} e
55492 "celldblclick" : true,
55495 * Fires when a row is clicked
55496 * @param {Grid} this
55497 * @param {Number} rowIndex
55498 * @param {Roo.EventObject} e
55502 * @event rowdblclick
55503 * Fires when a row is double clicked
55504 * @param {Grid} this
55505 * @param {Number} rowIndex
55506 * @param {Roo.EventObject} e
55508 "rowdblclick" : true,
55510 * @event headerclick
55511 * Fires when a header is clicked
55512 * @param {Grid} this
55513 * @param {Number} columnIndex
55514 * @param {Roo.EventObject} e
55516 "headerclick" : true,
55518 * @event headerdblclick
55519 * Fires when a header cell is double clicked
55520 * @param {Grid} this
55521 * @param {Number} columnIndex
55522 * @param {Roo.EventObject} e
55524 "headerdblclick" : true,
55526 * @event rowcontextmenu
55527 * Fires when a row is right clicked
55528 * @param {Grid} this
55529 * @param {Number} rowIndex
55530 * @param {Roo.EventObject} e
55532 "rowcontextmenu" : true,
55534 * @event cellcontextmenu
55535 * Fires when a cell is right clicked
55536 * @param {Grid} this
55537 * @param {Number} rowIndex
55538 * @param {Number} cellIndex
55539 * @param {Roo.EventObject} e
55541 "cellcontextmenu" : true,
55543 * @event headercontextmenu
55544 * Fires when a header is right clicked
55545 * @param {Grid} this
55546 * @param {Number} columnIndex
55547 * @param {Roo.EventObject} e
55549 "headercontextmenu" : true,
55551 * @event bodyscroll
55552 * Fires when the body element is scrolled
55553 * @param {Number} scrollLeft
55554 * @param {Number} scrollTop
55556 "bodyscroll" : true,
55558 * @event columnresize
55559 * Fires when the user resizes a column
55560 * @param {Number} columnIndex
55561 * @param {Number} newSize
55563 "columnresize" : true,
55565 * @event columnmove
55566 * Fires when the user moves a column
55567 * @param {Number} oldIndex
55568 * @param {Number} newIndex
55570 "columnmove" : true,
55573 * Fires when row(s) start being dragged
55574 * @param {Grid} this
55575 * @param {Roo.GridDD} dd The drag drop object
55576 * @param {event} e The raw browser event
55578 "startdrag" : true,
55581 * Fires when a drag operation is complete
55582 * @param {Grid} this
55583 * @param {Roo.GridDD} dd The drag drop object
55584 * @param {event} e The raw browser event
55589 * Fires when dragged row(s) are dropped on a valid DD target
55590 * @param {Grid} this
55591 * @param {Roo.GridDD} dd The drag drop object
55592 * @param {String} targetId The target drag drop object
55593 * @param {event} e The raw browser event
55598 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
55599 * @param {Grid} this
55600 * @param {Roo.GridDD} dd The drag drop object
55601 * @param {String} targetId The target drag drop object
55602 * @param {event} e The raw browser event
55607 * Fires when the dragged row(s) first cross another DD target while being dragged
55608 * @param {Grid} this
55609 * @param {Roo.GridDD} dd The drag drop object
55610 * @param {String} targetId The target drag drop object
55611 * @param {event} e The raw browser event
55613 "dragenter" : true,
55616 * Fires when the dragged row(s) leave another DD target while being dragged
55617 * @param {Grid} this
55618 * @param {Roo.GridDD} dd The drag drop object
55619 * @param {String} targetId The target drag drop object
55620 * @param {event} e The raw browser event
55625 * Fires when a row is rendered, so you can change add a style to it.
55626 * @param {GridView} gridview The grid view
55627 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
55633 * Fires when the grid is rendered
55634 * @param {Grid} grid
55639 Roo.grid.Grid.superclass.constructor.call(this);
55641 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
55644 * @cfg {Roo.grid.AbstractSelectionModel} sm The selection Model (default = Roo.grid.RowSelectionModel)
55647 * @cfg {Roo.grid.GridView} view The view that renders the grid (default = Roo.grid.GridView)
55650 * @cfg {Roo.grid.ColumnModel} cm[] The columns of the grid
55653 * @cfg {Roo.grid.Store} ds The data store for the grid
55656 * @cfg {Roo.Toolbar} toolbar a toolbar for buttons etc.
55659 * @cfg {String} ddGroup - drag drop group.
55662 * @cfg {String} dragGroup - drag group (?? not sure if needed.)
55666 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
55668 minColumnWidth : 25,
55671 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
55672 * <b>on initial render.</b> It is more efficient to explicitly size the columns
55673 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
55675 autoSizeColumns : false,
55678 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
55680 autoSizeHeaders : true,
55683 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
55685 monitorWindowResize : true,
55688 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
55689 * rows measured to get a columns size. Default is 0 (all rows).
55691 maxRowsToMeasure : 0,
55694 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
55696 trackMouseOver : true,
55699 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
55702 * @cfg {Boolean} enableDrop True to enable drop of elements. Default is false. (double check if this is needed?)
55706 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
55708 enableDragDrop : false,
55711 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
55713 enableColumnMove : true,
55716 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
55718 enableColumnHide : true,
55721 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
55723 enableRowHeightSync : false,
55726 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
55731 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
55733 autoHeight : false,
55736 * @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.
55738 autoExpandColumn : false,
55741 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
55744 autoExpandMin : 50,
55747 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
55749 autoExpandMax : 1000,
55752 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
55757 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
55761 * @cfg {Roo.dd.DropTarget} dropTarget An {@link Roo.dd.DropTarget} config
55771 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
55772 * of a fixed width. Default is false.
55775 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
55780 * @cfg {String} ddText Configures the text is the drag proxy (defaults to "%0 selected row(s)").
55781 * %0 is replaced with the number of selected rows.
55783 ddText : "{0} selected row{1}",
55787 * Called once after all setup has been completed and the grid is ready to be rendered.
55788 * @return {Roo.grid.Grid} this
55790 render : function()
55792 var c = this.container;
55793 // try to detect autoHeight/width mode
55794 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
55795 this.autoHeight = true;
55797 var view = this.getView();
55800 c.on("click", this.onClick, this);
55801 c.on("dblclick", this.onDblClick, this);
55802 c.on("contextmenu", this.onContextMenu, this);
55803 c.on("keydown", this.onKeyDown, this);
55805 c.on("touchstart", this.onTouchStart, this);
55808 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
55810 this.getSelectionModel().init(this);
55815 this.loadMask = new Roo.LoadMask(this.container,
55816 Roo.apply({store:this.dataSource}, this.loadMask));
55820 if (this.toolbar && this.toolbar.xtype) {
55821 this.toolbar.container = this.getView().getHeaderPanel(true);
55822 this.toolbar = new Roo.Toolbar(this.toolbar);
55824 if (this.footer && this.footer.xtype) {
55825 this.footer.dataSource = this.getDataSource();
55826 this.footer.container = this.getView().getFooterPanel(true);
55827 this.footer = Roo.factory(this.footer, Roo);
55829 if (this.dropTarget && this.dropTarget.xtype) {
55830 delete this.dropTarget.xtype;
55831 this.dropTarget = new Roo.dd.DropTarget(this.getView().mainBody, this.dropTarget);
55835 this.rendered = true;
55836 this.fireEvent('render', this);
55841 * Reconfigures the grid to use a different Store and Column Model.
55842 * The View will be bound to the new objects and refreshed.
55843 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
55844 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
55846 reconfigure : function(dataSource, colModel){
55848 this.loadMask.destroy();
55849 this.loadMask = new Roo.LoadMask(this.container,
55850 Roo.apply({store:dataSource}, this.loadMask));
55852 this.view.bind(dataSource, colModel);
55853 this.dataSource = dataSource;
55854 this.colModel = colModel;
55855 this.view.refresh(true);
55859 * Add's a column, default at the end..
55861 * @param {int} position to add (default end)
55862 * @param {Array} of objects of column configuration see {@link Roo.grid.ColumnModel}
55864 addColumns : function(pos, ar)
55867 for (var i =0;i< ar.length;i++) {
55869 cfg.id = typeof(cfg.id) == 'undefined' ? Roo.id() : cfg.id; // don't normally use this..
55870 this.cm.lookup[cfg.id] = cfg;
55874 if (typeof(pos) == 'undefined' || pos >= this.cm.config.length) {
55875 pos = this.cm.config.length; //this.cm.config.push(cfg);
55877 pos = Math.max(0,pos);
55880 this.cm.config.splice.apply(this.cm.config, ar);
55884 this.view.generateRules(this.cm);
55885 this.view.refresh(true);
55893 onKeyDown : function(e){
55894 this.fireEvent("keydown", e);
55898 * Destroy this grid.
55899 * @param {Boolean} removeEl True to remove the element
55901 destroy : function(removeEl, keepListeners){
55903 this.loadMask.destroy();
55905 var c = this.container;
55906 c.removeAllListeners();
55907 this.view.destroy();
55908 this.colModel.purgeListeners();
55909 if(!keepListeners){
55910 this.purgeListeners();
55913 if(removeEl === true){
55919 processEvent : function(name, e){
55920 // does this fire select???
55921 //Roo.log('grid:processEvent ' + name);
55923 if (name != 'touchstart' ) {
55924 this.fireEvent(name, e);
55927 var t = e.getTarget();
55929 var header = v.findHeaderIndex(t);
55930 if(header !== false){
55931 var ename = name == 'touchstart' ? 'click' : name;
55933 this.fireEvent("header" + ename, this, header, e);
55935 var row = v.findRowIndex(t);
55936 var cell = v.findCellIndex(t);
55937 if (name == 'touchstart') {
55938 // first touch is always a click.
55939 // hopefull this happens after selection is updated.?
55942 if (typeof(this.selModel.getSelectedCell) != 'undefined') {
55943 var cs = this.selModel.getSelectedCell();
55944 if (row == cs[0] && cell == cs[1]){
55948 if (typeof(this.selModel.getSelections) != 'undefined') {
55949 var cs = this.selModel.getSelections();
55950 var ds = this.dataSource;
55951 if (cs.length == 1 && ds.getAt(row) == cs[0]){
55962 this.fireEvent("row" + name, this, row, e);
55963 if(cell !== false){
55964 this.fireEvent("cell" + name, this, row, cell, e);
55971 onClick : function(e){
55972 this.processEvent("click", e);
55975 onTouchStart : function(e){
55976 this.processEvent("touchstart", e);
55980 onContextMenu : function(e, t){
55981 this.processEvent("contextmenu", e);
55985 onDblClick : function(e){
55986 this.processEvent("dblclick", e);
55990 walkCells : function(row, col, step, fn, scope){
55991 var cm = this.colModel, clen = cm.getColumnCount();
55992 var ds = this.dataSource, rlen = ds.getCount(), first = true;
56004 if(fn.call(scope || this, row, col, cm) === true){
56022 if(fn.call(scope || this, row, col, cm) === true){
56034 getSelections : function(){
56035 return this.selModel.getSelections();
56039 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
56040 * but if manual update is required this method will initiate it.
56042 autoSize : function(){
56044 this.view.layout();
56045 if(this.view.adjustForScroll){
56046 this.view.adjustForScroll();
56052 * Returns the grid's underlying element.
56053 * @return {Element} The element
56055 getGridEl : function(){
56056 return this.container;
56059 // private for compatibility, overridden by editor grid
56060 stopEditing : function(){},
56063 * Returns the grid's SelectionModel.
56064 * @return {SelectionModel}
56066 getSelectionModel : function(){
56067 if(!this.selModel){
56068 this.selModel = new Roo.grid.RowSelectionModel();
56070 return this.selModel;
56074 * Returns the grid's DataSource.
56075 * @return {DataSource}
56077 getDataSource : function(){
56078 return this.dataSource;
56082 * Returns the grid's ColumnModel.
56083 * @return {ColumnModel}
56085 getColumnModel : function(){
56086 return this.colModel;
56090 * Returns the grid's GridView object.
56091 * @return {GridView}
56093 getView : function(){
56095 this.view = new Roo.grid.GridView(this.viewConfig);
56096 this.relayEvents(this.view, [
56097 "beforerowremoved", "beforerowsinserted",
56098 "beforerefresh", "rowremoved",
56099 "rowsinserted", "rowupdated" ,"refresh"
56105 * Called to get grid's drag proxy text, by default returns this.ddText.
56106 * Override this to put something different in the dragged text.
56109 getDragDropText : function(){
56110 var count = this.selModel.getCount();
56111 return String.format(this.ddText, count, count == 1 ? '' : 's');
56116 * Ext JS Library 1.1.1
56117 * Copyright(c) 2006-2007, Ext JS, LLC.
56119 * Originally Released Under LGPL - original licence link has changed is not relivant.
56122 * <script type="text/javascript">
56125 * @class Roo.grid.AbstractGridView
56126 * @extends Roo.util.Observable
56128 * Abstract base class for grid Views
56131 Roo.grid.AbstractGridView = function(){
56135 "beforerowremoved" : true,
56136 "beforerowsinserted" : true,
56137 "beforerefresh" : true,
56138 "rowremoved" : true,
56139 "rowsinserted" : true,
56140 "rowupdated" : true,
56143 Roo.grid.AbstractGridView.superclass.constructor.call(this);
56146 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
56147 rowClass : "x-grid-row",
56148 cellClass : "x-grid-cell",
56149 tdClass : "x-grid-td",
56150 hdClass : "x-grid-hd",
56151 splitClass : "x-grid-hd-split",
56153 init: function(grid){
56155 var cid = this.grid.getGridEl().id;
56156 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
56157 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
56158 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
56159 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
56162 getColumnRenderers : function(){
56163 var renderers = [];
56164 var cm = this.grid.colModel;
56165 var colCount = cm.getColumnCount();
56166 for(var i = 0; i < colCount; i++){
56167 renderers[i] = cm.getRenderer(i);
56172 getColumnIds : function(){
56174 var cm = this.grid.colModel;
56175 var colCount = cm.getColumnCount();
56176 for(var i = 0; i < colCount; i++){
56177 ids[i] = cm.getColumnId(i);
56182 getDataIndexes : function(){
56183 if(!this.indexMap){
56184 this.indexMap = this.buildIndexMap();
56186 return this.indexMap.colToData;
56189 getColumnIndexByDataIndex : function(dataIndex){
56190 if(!this.indexMap){
56191 this.indexMap = this.buildIndexMap();
56193 return this.indexMap.dataToCol[dataIndex];
56197 * Set a css style for a column dynamically.
56198 * @param {Number} colIndex The index of the column
56199 * @param {String} name The css property name
56200 * @param {String} value The css value
56202 setCSSStyle : function(colIndex, name, value){
56203 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
56204 Roo.util.CSS.updateRule(selector, name, value);
56207 generateRules : function(cm){
56208 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
56209 Roo.util.CSS.removeStyleSheet(rulesId);
56210 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
56211 var cid = cm.getColumnId(i);
56212 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
56213 this.tdSelector, cid, " {\n}\n",
56214 this.hdSelector, cid, " {\n}\n",
56215 this.splitSelector, cid, " {\n}\n");
56217 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
56221 * Ext JS Library 1.1.1
56222 * Copyright(c) 2006-2007, Ext JS, LLC.
56224 * Originally Released Under LGPL - original licence link has changed is not relivant.
56227 * <script type="text/javascript">
56231 // This is a support class used internally by the Grid components
56232 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
56234 this.view = grid.getView();
56235 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
56236 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
56238 this.setHandleElId(Roo.id(hd));
56239 this.setOuterHandleElId(Roo.id(hd2));
56241 this.scroll = false;
56243 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
56245 getDragData : function(e){
56246 var t = Roo.lib.Event.getTarget(e);
56247 var h = this.view.findHeaderCell(t);
56249 return {ddel: h.firstChild, header:h};
56254 onInitDrag : function(e){
56255 this.view.headersDisabled = true;
56256 var clone = this.dragData.ddel.cloneNode(true);
56257 clone.id = Roo.id();
56258 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
56259 this.proxy.update(clone);
56263 afterValidDrop : function(){
56265 setTimeout(function(){
56266 v.headersDisabled = false;
56270 afterInvalidDrop : function(){
56272 setTimeout(function(){
56273 v.headersDisabled = false;
56279 * Ext JS Library 1.1.1
56280 * Copyright(c) 2006-2007, Ext JS, LLC.
56282 * Originally Released Under LGPL - original licence link has changed is not relivant.
56285 * <script type="text/javascript">
56288 // This is a support class used internally by the Grid components
56289 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
56291 this.view = grid.getView();
56292 // split the proxies so they don't interfere with mouse events
56293 this.proxyTop = Roo.DomHelper.append(document.body, {
56294 cls:"col-move-top", html:" "
56296 this.proxyBottom = Roo.DomHelper.append(document.body, {
56297 cls:"col-move-bottom", html:" "
56299 this.proxyTop.hide = this.proxyBottom.hide = function(){
56300 this.setLeftTop(-100,-100);
56301 this.setStyle("visibility", "hidden");
56303 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
56304 // temporarily disabled
56305 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
56306 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
56308 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
56309 proxyOffsets : [-4, -9],
56310 fly: Roo.Element.fly,
56312 getTargetFromEvent : function(e){
56313 var t = Roo.lib.Event.getTarget(e);
56314 var cindex = this.view.findCellIndex(t);
56315 if(cindex !== false){
56316 return this.view.getHeaderCell(cindex);
56321 nextVisible : function(h){
56322 var v = this.view, cm = this.grid.colModel;
56325 if(!cm.isHidden(v.getCellIndex(h))){
56333 prevVisible : function(h){
56334 var v = this.view, cm = this.grid.colModel;
56337 if(!cm.isHidden(v.getCellIndex(h))){
56345 positionIndicator : function(h, n, e){
56346 var x = Roo.lib.Event.getPageX(e);
56347 var r = Roo.lib.Dom.getRegion(n.firstChild);
56348 var px, pt, py = r.top + this.proxyOffsets[1];
56349 if((r.right - x) <= (r.right-r.left)/2){
56350 px = r.right+this.view.borderWidth;
56356 var oldIndex = this.view.getCellIndex(h);
56357 var newIndex = this.view.getCellIndex(n);
56359 if(this.grid.colModel.isFixed(newIndex)){
56363 var locked = this.grid.colModel.isLocked(newIndex);
56368 if(oldIndex < newIndex){
56371 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
56374 px += this.proxyOffsets[0];
56375 this.proxyTop.setLeftTop(px, py);
56376 this.proxyTop.show();
56377 if(!this.bottomOffset){
56378 this.bottomOffset = this.view.mainHd.getHeight();
56380 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
56381 this.proxyBottom.show();
56385 onNodeEnter : function(n, dd, e, data){
56386 if(data.header != n){
56387 this.positionIndicator(data.header, n, e);
56391 onNodeOver : function(n, dd, e, data){
56392 var result = false;
56393 if(data.header != n){
56394 result = this.positionIndicator(data.header, n, e);
56397 this.proxyTop.hide();
56398 this.proxyBottom.hide();
56400 return result ? this.dropAllowed : this.dropNotAllowed;
56403 onNodeOut : function(n, dd, e, data){
56404 this.proxyTop.hide();
56405 this.proxyBottom.hide();
56408 onNodeDrop : function(n, dd, e, data){
56409 var h = data.header;
56411 var cm = this.grid.colModel;
56412 var x = Roo.lib.Event.getPageX(e);
56413 var r = Roo.lib.Dom.getRegion(n.firstChild);
56414 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
56415 var oldIndex = this.view.getCellIndex(h);
56416 var newIndex = this.view.getCellIndex(n);
56417 var locked = cm.isLocked(newIndex);
56421 if(oldIndex < newIndex){
56424 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
56427 cm.setLocked(oldIndex, locked, true);
56428 cm.moveColumn(oldIndex, newIndex);
56429 this.grid.fireEvent("columnmove", oldIndex, newIndex);
56437 * Ext JS Library 1.1.1
56438 * Copyright(c) 2006-2007, Ext JS, LLC.
56440 * Originally Released Under LGPL - original licence link has changed is not relivant.
56443 * <script type="text/javascript">
56447 * @class Roo.grid.GridView
56448 * @extends Roo.util.Observable
56451 * @param {Object} config
56453 Roo.grid.GridView = function(config){
56454 Roo.grid.GridView.superclass.constructor.call(this);
56457 Roo.apply(this, config);
56460 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
56462 unselectable : 'unselectable="on"',
56463 unselectableCls : 'x-unselectable',
56466 rowClass : "x-grid-row",
56468 cellClass : "x-grid-col",
56470 tdClass : "x-grid-td",
56472 hdClass : "x-grid-hd",
56474 splitClass : "x-grid-split",
56476 sortClasses : ["sort-asc", "sort-desc"],
56478 enableMoveAnim : false,
56482 dh : Roo.DomHelper,
56484 fly : Roo.Element.fly,
56486 css : Roo.util.CSS,
56492 scrollIncrement : 22,
56494 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
56496 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
56498 bind : function(ds, cm){
56500 this.ds.un("load", this.onLoad, this);
56501 this.ds.un("datachanged", this.onDataChange, this);
56502 this.ds.un("add", this.onAdd, this);
56503 this.ds.un("remove", this.onRemove, this);
56504 this.ds.un("update", this.onUpdate, this);
56505 this.ds.un("clear", this.onClear, this);
56508 ds.on("load", this.onLoad, this);
56509 ds.on("datachanged", this.onDataChange, this);
56510 ds.on("add", this.onAdd, this);
56511 ds.on("remove", this.onRemove, this);
56512 ds.on("update", this.onUpdate, this);
56513 ds.on("clear", this.onClear, this);
56518 this.cm.un("widthchange", this.onColWidthChange, this);
56519 this.cm.un("headerchange", this.onHeaderChange, this);
56520 this.cm.un("hiddenchange", this.onHiddenChange, this);
56521 this.cm.un("columnmoved", this.onColumnMove, this);
56522 this.cm.un("columnlockchange", this.onColumnLock, this);
56525 this.generateRules(cm);
56526 cm.on("widthchange", this.onColWidthChange, this);
56527 cm.on("headerchange", this.onHeaderChange, this);
56528 cm.on("hiddenchange", this.onHiddenChange, this);
56529 cm.on("columnmoved", this.onColumnMove, this);
56530 cm.on("columnlockchange", this.onColumnLock, this);
56535 init: function(grid){
56536 Roo.grid.GridView.superclass.init.call(this, grid);
56538 this.bind(grid.dataSource, grid.colModel);
56540 grid.on("headerclick", this.handleHeaderClick, this);
56542 if(grid.trackMouseOver){
56543 grid.on("mouseover", this.onRowOver, this);
56544 grid.on("mouseout", this.onRowOut, this);
56546 grid.cancelTextSelection = function(){};
56547 this.gridId = grid.id;
56549 var tpls = this.templates || {};
56552 tpls.master = new Roo.Template(
56553 '<div class="x-grid" hidefocus="true">',
56554 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
56555 '<div class="x-grid-topbar"></div>',
56556 '<div class="x-grid-scroller"><div></div></div>',
56557 '<div class="x-grid-locked">',
56558 '<div class="x-grid-header">{lockedHeader}</div>',
56559 '<div class="x-grid-body">{lockedBody}</div>',
56561 '<div class="x-grid-viewport">',
56562 '<div class="x-grid-header">{header}</div>',
56563 '<div class="x-grid-body">{body}</div>',
56565 '<div class="x-grid-bottombar"></div>',
56567 '<div class="x-grid-resize-proxy"> </div>',
56570 tpls.master.disableformats = true;
56574 tpls.header = new Roo.Template(
56575 '<table border="0" cellspacing="0" cellpadding="0">',
56576 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
56579 tpls.header.disableformats = true;
56581 tpls.header.compile();
56584 tpls.hcell = new Roo.Template(
56585 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
56586 '<div class="x-grid-hd-text ' + this.unselectableCls + '" ' + this.unselectable +'>{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
56589 tpls.hcell.disableFormats = true;
56591 tpls.hcell.compile();
56594 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style} ' +
56595 this.unselectableCls + '" ' + this.unselectable +'> </div>');
56596 tpls.hsplit.disableFormats = true;
56598 tpls.hsplit.compile();
56601 tpls.body = new Roo.Template(
56602 '<table border="0" cellspacing="0" cellpadding="0">',
56603 "<tbody>{rows}</tbody>",
56606 tpls.body.disableFormats = true;
56608 tpls.body.compile();
56611 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
56612 tpls.row.disableFormats = true;
56614 tpls.row.compile();
56617 tpls.cell = new Roo.Template(
56618 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
56619 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text ' +
56620 this.unselectableCls + '" ' + this.unselectable +'" {attr}>{value}</div></div>',
56623 tpls.cell.disableFormats = true;
56625 tpls.cell.compile();
56627 this.templates = tpls;
56630 // remap these for backwards compat
56631 onColWidthChange : function(){
56632 this.updateColumns.apply(this, arguments);
56634 onHeaderChange : function(){
56635 this.updateHeaders.apply(this, arguments);
56637 onHiddenChange : function(){
56638 this.handleHiddenChange.apply(this, arguments);
56640 onColumnMove : function(){
56641 this.handleColumnMove.apply(this, arguments);
56643 onColumnLock : function(){
56644 this.handleLockChange.apply(this, arguments);
56647 onDataChange : function(){
56649 this.updateHeaderSortState();
56652 onClear : function(){
56656 onUpdate : function(ds, record){
56657 this.refreshRow(record);
56660 refreshRow : function(record){
56661 var ds = this.ds, index;
56662 if(typeof record == 'number'){
56664 record = ds.getAt(index);
56666 index = ds.indexOf(record);
56668 this.insertRows(ds, index, index, true);
56669 this.onRemove(ds, record, index+1, true);
56670 this.syncRowHeights(index, index);
56672 this.fireEvent("rowupdated", this, index, record);
56675 onAdd : function(ds, records, index){
56676 this.insertRows(ds, index, index + (records.length-1));
56679 onRemove : function(ds, record, index, isUpdate){
56680 if(isUpdate !== true){
56681 this.fireEvent("beforerowremoved", this, index, record);
56683 var bt = this.getBodyTable(), lt = this.getLockedTable();
56684 if(bt.rows[index]){
56685 bt.firstChild.removeChild(bt.rows[index]);
56687 if(lt.rows[index]){
56688 lt.firstChild.removeChild(lt.rows[index]);
56690 if(isUpdate !== true){
56691 this.stripeRows(index);
56692 this.syncRowHeights(index, index);
56694 this.fireEvent("rowremoved", this, index, record);
56698 onLoad : function(){
56699 this.scrollToTop();
56703 * Scrolls the grid to the top
56705 scrollToTop : function(){
56707 this.scroller.dom.scrollTop = 0;
56713 * Gets a panel in the header of the grid that can be used for toolbars etc.
56714 * After modifying the contents of this panel a call to grid.autoSize() may be
56715 * required to register any changes in size.
56716 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
56717 * @return Roo.Element
56719 getHeaderPanel : function(doShow){
56721 this.headerPanel.show();
56723 return this.headerPanel;
56727 * Gets a panel in the footer of the grid that can be used for toolbars etc.
56728 * After modifying the contents of this panel a call to grid.autoSize() may be
56729 * required to register any changes in size.
56730 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
56731 * @return Roo.Element
56733 getFooterPanel : function(doShow){
56735 this.footerPanel.show();
56737 return this.footerPanel;
56740 initElements : function(){
56741 var E = Roo.Element;
56742 var el = this.grid.getGridEl().dom.firstChild;
56743 var cs = el.childNodes;
56745 this.el = new E(el);
56747 this.focusEl = new E(el.firstChild);
56748 this.focusEl.swallowEvent("click", true);
56750 this.headerPanel = new E(cs[1]);
56751 this.headerPanel.enableDisplayMode("block");
56753 this.scroller = new E(cs[2]);
56754 this.scrollSizer = new E(this.scroller.dom.firstChild);
56756 this.lockedWrap = new E(cs[3]);
56757 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
56758 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
56760 this.mainWrap = new E(cs[4]);
56761 this.mainHd = new E(this.mainWrap.dom.firstChild);
56762 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
56764 this.footerPanel = new E(cs[5]);
56765 this.footerPanel.enableDisplayMode("block");
56767 this.resizeProxy = new E(cs[6]);
56769 this.headerSelector = String.format(
56770 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
56771 this.lockedHd.id, this.mainHd.id
56774 this.splitterSelector = String.format(
56775 '#{0} div.x-grid-split, #{1} div.x-grid-split',
56776 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
56779 idToCssName : function(s)
56781 return s.replace(/[^a-z0-9]+/ig, '-');
56784 getHeaderCell : function(index){
56785 return Roo.DomQuery.select(this.headerSelector)[index];
56788 getHeaderCellMeasure : function(index){
56789 return this.getHeaderCell(index).firstChild;
56792 getHeaderCellText : function(index){
56793 return this.getHeaderCell(index).firstChild.firstChild;
56796 getLockedTable : function(){
56797 return this.lockedBody.dom.firstChild;
56800 getBodyTable : function(){
56801 return this.mainBody.dom.firstChild;
56804 getLockedRow : function(index){
56805 return this.getLockedTable().rows[index];
56808 getRow : function(index){
56809 return this.getBodyTable().rows[index];
56812 getRowComposite : function(index){
56814 this.rowEl = new Roo.CompositeElementLite();
56816 var els = [], lrow, mrow;
56817 if(lrow = this.getLockedRow(index)){
56820 if(mrow = this.getRow(index)){
56823 this.rowEl.elements = els;
56827 * Gets the 'td' of the cell
56829 * @param {Integer} rowIndex row to select
56830 * @param {Integer} colIndex column to select
56834 getCell : function(rowIndex, colIndex){
56835 var locked = this.cm.getLockedCount();
56837 if(colIndex < locked){
56838 source = this.lockedBody.dom.firstChild;
56840 source = this.mainBody.dom.firstChild;
56841 colIndex -= locked;
56843 return source.rows[rowIndex].childNodes[colIndex];
56846 getCellText : function(rowIndex, colIndex){
56847 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
56850 getCellBox : function(cell){
56851 var b = this.fly(cell).getBox();
56852 if(Roo.isOpera){ // opera fails to report the Y
56853 b.y = cell.offsetTop + this.mainBody.getY();
56858 getCellIndex : function(cell){
56859 var id = String(cell.className).match(this.cellRE);
56861 return parseInt(id[1], 10);
56866 findHeaderIndex : function(n){
56867 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
56868 return r ? this.getCellIndex(r) : false;
56871 findHeaderCell : function(n){
56872 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
56873 return r ? r : false;
56876 findRowIndex : function(n){
56880 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
56881 return r ? r.rowIndex : false;
56884 findCellIndex : function(node){
56885 var stop = this.el.dom;
56886 while(node && node != stop){
56887 if(this.findRE.test(node.className)){
56888 return this.getCellIndex(node);
56890 node = node.parentNode;
56895 getColumnId : function(index){
56896 return this.cm.getColumnId(index);
56899 getSplitters : function()
56901 if(this.splitterSelector){
56902 return Roo.DomQuery.select(this.splitterSelector);
56908 getSplitter : function(index){
56909 return this.getSplitters()[index];
56912 onRowOver : function(e, t){
56914 if((row = this.findRowIndex(t)) !== false){
56915 this.getRowComposite(row).addClass("x-grid-row-over");
56919 onRowOut : function(e, t){
56921 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
56922 this.getRowComposite(row).removeClass("x-grid-row-over");
56926 renderHeaders : function(){
56928 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
56929 var cb = [], lb = [], sb = [], lsb = [], p = {};
56930 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
56931 p.cellId = "x-grid-hd-0-" + i;
56932 p.splitId = "x-grid-csplit-0-" + i;
56933 p.id = cm.getColumnId(i);
56934 p.value = cm.getColumnHeader(i) || "";
56935 p.title = cm.getColumnTooltip(i) || (''+p.value).match(/\</) ? '' : p.value || "";
56936 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
56937 if(!cm.isLocked(i)){
56938 cb[cb.length] = ct.apply(p);
56939 sb[sb.length] = st.apply(p);
56941 lb[lb.length] = ct.apply(p);
56942 lsb[lsb.length] = st.apply(p);
56945 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
56946 ht.apply({cells: cb.join(""), splits:sb.join("")})];
56949 updateHeaders : function(){
56950 var html = this.renderHeaders();
56951 this.lockedHd.update(html[0]);
56952 this.mainHd.update(html[1]);
56956 * Focuses the specified row.
56957 * @param {Number} row The row index
56959 focusRow : function(row)
56961 //Roo.log('GridView.focusRow');
56962 var x = this.scroller.dom.scrollLeft;
56963 this.focusCell(row, 0, false);
56964 this.scroller.dom.scrollLeft = x;
56968 * Focuses the specified cell.
56969 * @param {Number} row The row index
56970 * @param {Number} col The column index
56971 * @param {Boolean} hscroll false to disable horizontal scrolling
56973 focusCell : function(row, col, hscroll)
56975 //Roo.log('GridView.focusCell');
56976 var el = this.ensureVisible(row, col, hscroll);
56977 this.focusEl.alignTo(el, "tl-tl");
56979 this.focusEl.focus();
56981 this.focusEl.focus.defer(1, this.focusEl);
56986 * Scrolls the specified cell into view
56987 * @param {Number} row The row index
56988 * @param {Number} col The column index
56989 * @param {Boolean} hscroll false to disable horizontal scrolling
56991 ensureVisible : function(row, col, hscroll)
56993 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
56994 //return null; //disable for testing.
56995 if(typeof row != "number"){
56996 row = row.rowIndex;
56998 if(row < 0 && row >= this.ds.getCount()){
57001 col = (col !== undefined ? col : 0);
57002 var cm = this.grid.colModel;
57003 while(cm.isHidden(col)){
57007 var el = this.getCell(row, col);
57011 var c = this.scroller.dom;
57013 var ctop = parseInt(el.offsetTop, 10);
57014 var cleft = parseInt(el.offsetLeft, 10);
57015 var cbot = ctop + el.offsetHeight;
57016 var cright = cleft + el.offsetWidth;
57018 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
57019 var stop = parseInt(c.scrollTop, 10);
57020 var sleft = parseInt(c.scrollLeft, 10);
57021 var sbot = stop + ch;
57022 var sright = sleft + c.clientWidth;
57024 Roo.log('GridView.ensureVisible:' +
57026 ' c.clientHeight:' + c.clientHeight +
57027 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
57035 c.scrollTop = ctop;
57036 //Roo.log("set scrolltop to ctop DISABLE?");
57037 }else if(cbot > sbot){
57038 //Roo.log("set scrolltop to cbot-ch");
57039 c.scrollTop = cbot-ch;
57042 if(hscroll !== false){
57044 c.scrollLeft = cleft;
57045 }else if(cright > sright){
57046 c.scrollLeft = cright-c.clientWidth;
57053 updateColumns : function(){
57054 this.grid.stopEditing();
57055 var cm = this.grid.colModel, colIds = this.getColumnIds();
57056 //var totalWidth = cm.getTotalWidth();
57058 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
57059 //if(cm.isHidden(i)) continue;
57060 var w = cm.getColumnWidth(i);
57061 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
57062 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
57064 this.updateSplitters();
57067 generateRules : function(cm){
57068 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
57069 Roo.util.CSS.removeStyleSheet(rulesId);
57070 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
57071 var cid = cm.getColumnId(i);
57073 if(cm.config[i].align){
57074 align = 'text-align:'+cm.config[i].align+';';
57077 if(cm.isHidden(i)){
57078 hidden = 'display:none;';
57080 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
57082 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
57083 this.hdSelector, cid, " {\n", align, width, "}\n",
57084 this.tdSelector, cid, " {\n",hidden,"\n}\n",
57085 this.splitSelector, cid, " {\n", hidden , "\n}\n");
57087 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
57090 updateSplitters : function(){
57091 var cm = this.cm, s = this.getSplitters();
57092 if(s){ // splitters not created yet
57093 var pos = 0, locked = true;
57094 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
57095 if(cm.isHidden(i)) {
57098 var w = cm.getColumnWidth(i); // make sure it's a number
57099 if(!cm.isLocked(i) && locked){
57104 s[i].style.left = (pos-this.splitOffset) + "px";
57109 handleHiddenChange : function(colModel, colIndex, hidden){
57111 this.hideColumn(colIndex);
57113 this.unhideColumn(colIndex);
57117 hideColumn : function(colIndex){
57118 var cid = this.getColumnId(colIndex);
57119 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
57120 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
57122 this.updateHeaders();
57124 this.updateSplitters();
57128 unhideColumn : function(colIndex){
57129 var cid = this.getColumnId(colIndex);
57130 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
57131 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
57134 this.updateHeaders();
57136 this.updateSplitters();
57140 insertRows : function(dm, firstRow, lastRow, isUpdate){
57141 if(firstRow == 0 && lastRow == dm.getCount()-1){
57145 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
57147 var s = this.getScrollState();
57148 var markup = this.renderRows(firstRow, lastRow);
57149 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
57150 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
57151 this.restoreScroll(s);
57153 this.fireEvent("rowsinserted", this, firstRow, lastRow);
57154 this.syncRowHeights(firstRow, lastRow);
57155 this.stripeRows(firstRow);
57161 bufferRows : function(markup, target, index){
57162 var before = null, trows = target.rows, tbody = target.tBodies[0];
57163 if(index < trows.length){
57164 before = trows[index];
57166 var b = document.createElement("div");
57167 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
57168 var rows = b.firstChild.rows;
57169 for(var i = 0, len = rows.length; i < len; i++){
57171 tbody.insertBefore(rows[0], before);
57173 tbody.appendChild(rows[0]);
57180 deleteRows : function(dm, firstRow, lastRow){
57181 if(dm.getRowCount()<1){
57182 this.fireEvent("beforerefresh", this);
57183 this.mainBody.update("");
57184 this.lockedBody.update("");
57185 this.fireEvent("refresh", this);
57187 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
57188 var bt = this.getBodyTable();
57189 var tbody = bt.firstChild;
57190 var rows = bt.rows;
57191 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
57192 tbody.removeChild(rows[firstRow]);
57194 this.stripeRows(firstRow);
57195 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
57199 updateRows : function(dataSource, firstRow, lastRow){
57200 var s = this.getScrollState();
57202 this.restoreScroll(s);
57205 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
57209 this.updateHeaderSortState();
57212 getScrollState : function(){
57214 var sb = this.scroller.dom;
57215 return {left: sb.scrollLeft, top: sb.scrollTop};
57218 stripeRows : function(startRow){
57219 if(!this.grid.stripeRows || this.ds.getCount() < 1){
57222 startRow = startRow || 0;
57223 var rows = this.getBodyTable().rows;
57224 var lrows = this.getLockedTable().rows;
57225 var cls = ' x-grid-row-alt ';
57226 for(var i = startRow, len = rows.length; i < len; i++){
57227 var row = rows[i], lrow = lrows[i];
57228 var isAlt = ((i+1) % 2 == 0);
57229 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
57230 if(isAlt == hasAlt){
57234 row.className += " x-grid-row-alt";
57236 row.className = row.className.replace("x-grid-row-alt", "");
57239 lrow.className = row.className;
57244 restoreScroll : function(state){
57245 //Roo.log('GridView.restoreScroll');
57246 var sb = this.scroller.dom;
57247 sb.scrollLeft = state.left;
57248 sb.scrollTop = state.top;
57252 syncScroll : function(){
57253 //Roo.log('GridView.syncScroll');
57254 var sb = this.scroller.dom;
57255 var sh = this.mainHd.dom;
57256 var bs = this.mainBody.dom;
57257 var lv = this.lockedBody.dom;
57258 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
57259 lv.scrollTop = bs.scrollTop = sb.scrollTop;
57262 handleScroll : function(e){
57264 var sb = this.scroller.dom;
57265 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
57269 handleWheel : function(e){
57270 var d = e.getWheelDelta();
57271 this.scroller.dom.scrollTop -= d*22;
57272 // set this here to prevent jumpy scrolling on large tables
57273 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
57277 renderRows : function(startRow, endRow){
57278 // pull in all the crap needed to render rows
57279 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
57280 var colCount = cm.getColumnCount();
57282 if(ds.getCount() < 1){
57286 // build a map for all the columns
57288 for(var i = 0; i < colCount; i++){
57289 var name = cm.getDataIndex(i);
57291 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
57292 renderer : cm.getRenderer(i),
57293 id : cm.getColumnId(i),
57294 locked : cm.isLocked(i),
57295 has_editor : cm.isCellEditable(i)
57299 startRow = startRow || 0;
57300 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
57302 // records to render
57303 var rs = ds.getRange(startRow, endRow);
57305 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
57308 // As much as I hate to duplicate code, this was branched because FireFox really hates
57309 // [].join("") on strings. The performance difference was substantial enough to
57310 // branch this function
57311 doRender : Roo.isGecko ?
57312 function(cs, rs, ds, startRow, colCount, stripe){
57313 var ts = this.templates, ct = ts.cell, rt = ts.row;
57315 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
57317 var hasListener = this.grid.hasListener('rowclass');
57319 for(var j = 0, len = rs.length; j < len; j++){
57320 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
57321 for(var i = 0; i < colCount; i++){
57323 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
57325 p.css = p.attr = "";
57326 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
57327 if(p.value == undefined || p.value === "") {
57328 p.value = " ";
57331 p.css += ' x-grid-editable-cell';
57333 if(c.dirty && typeof r.modified[c.name] !== 'undefined'){
57334 p.css += ' x-grid-dirty-cell';
57336 var markup = ct.apply(p);
57344 if(stripe && ((rowIndex+1) % 2 == 0)){
57345 alt.push("x-grid-row-alt")
57348 alt.push( " x-grid-dirty-row");
57351 if(this.getRowClass){
57352 alt.push(this.getRowClass(r, rowIndex));
57358 rowIndex : rowIndex,
57361 this.grid.fireEvent('rowclass', this, rowcfg);
57362 alt.push(rowcfg.rowClass);
57364 rp.alt = alt.join(" ");
57365 lbuf+= rt.apply(rp);
57367 buf+= rt.apply(rp);
57369 return [lbuf, buf];
57371 function(cs, rs, ds, startRow, colCount, stripe){
57372 var ts = this.templates, ct = ts.cell, rt = ts.row;
57374 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
57375 var hasListener = this.grid.hasListener('rowclass');
57378 for(var j = 0, len = rs.length; j < len; j++){
57379 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
57380 for(var i = 0; i < colCount; i++){
57382 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
57384 p.css = p.attr = "";
57385 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
57386 if(p.value == undefined || p.value === "") {
57387 p.value = " ";
57391 p.css += ' x-grid-editable-cell';
57393 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
57394 p.css += ' x-grid-dirty-cell'
57397 var markup = ct.apply(p);
57399 cb[cb.length] = markup;
57401 lcb[lcb.length] = markup;
57405 if(stripe && ((rowIndex+1) % 2 == 0)){
57406 alt.push( "x-grid-row-alt");
57409 alt.push(" x-grid-dirty-row");
57412 if(this.getRowClass){
57413 alt.push( this.getRowClass(r, rowIndex));
57419 rowIndex : rowIndex,
57422 this.grid.fireEvent('rowclass', this, rowcfg);
57423 alt.push(rowcfg.rowClass);
57426 rp.alt = alt.join(" ");
57427 rp.cells = lcb.join("");
57428 lbuf[lbuf.length] = rt.apply(rp);
57429 rp.cells = cb.join("");
57430 buf[buf.length] = rt.apply(rp);
57432 return [lbuf.join(""), buf.join("")];
57435 renderBody : function(){
57436 var markup = this.renderRows();
57437 var bt = this.templates.body;
57438 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
57442 * Refreshes the grid
57443 * @param {Boolean} headersToo
57445 refresh : function(headersToo){
57446 this.fireEvent("beforerefresh", this);
57447 this.grid.stopEditing();
57448 var result = this.renderBody();
57449 this.lockedBody.update(result[0]);
57450 this.mainBody.update(result[1]);
57451 if(headersToo === true){
57452 this.updateHeaders();
57453 this.updateColumns();
57454 this.updateSplitters();
57455 this.updateHeaderSortState();
57457 this.syncRowHeights();
57459 this.fireEvent("refresh", this);
57462 handleColumnMove : function(cm, oldIndex, newIndex){
57463 this.indexMap = null;
57464 var s = this.getScrollState();
57465 this.refresh(true);
57466 this.restoreScroll(s);
57467 this.afterMove(newIndex);
57470 afterMove : function(colIndex){
57471 if(this.enableMoveAnim && Roo.enableFx){
57472 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
57474 // if multisort - fix sortOrder, and reload..
57475 if (this.grid.dataSource.multiSort) {
57476 // the we can call sort again..
57477 var dm = this.grid.dataSource;
57478 var cm = this.grid.colModel;
57480 for(var i = 0; i < cm.config.length; i++ ) {
57482 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
57483 continue; // dont' bother, it's not in sort list or being set.
57486 so.push(cm.config[i].dataIndex);
57489 dm.load(dm.lastOptions);
57496 updateCell : function(dm, rowIndex, dataIndex){
57497 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
57498 if(typeof colIndex == "undefined"){ // not present in grid
57501 var cm = this.grid.colModel;
57502 var cell = this.getCell(rowIndex, colIndex);
57503 var cellText = this.getCellText(rowIndex, colIndex);
57506 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
57507 id : cm.getColumnId(colIndex),
57508 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
57510 var renderer = cm.getRenderer(colIndex);
57511 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
57512 if(typeof val == "undefined" || val === "") {
57515 cellText.innerHTML = val;
57516 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
57517 this.syncRowHeights(rowIndex, rowIndex);
57520 calcColumnWidth : function(colIndex, maxRowsToMeasure){
57522 if(this.grid.autoSizeHeaders){
57523 var h = this.getHeaderCellMeasure(colIndex);
57524 maxWidth = Math.max(maxWidth, h.scrollWidth);
57527 if(this.cm.isLocked(colIndex)){
57528 tb = this.getLockedTable();
57531 tb = this.getBodyTable();
57532 index = colIndex - this.cm.getLockedCount();
57535 var rows = tb.rows;
57536 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
57537 for(var i = 0; i < stopIndex; i++){
57538 var cell = rows[i].childNodes[index].firstChild;
57539 maxWidth = Math.max(maxWidth, cell.scrollWidth);
57542 return maxWidth + /*margin for error in IE*/ 5;
57545 * Autofit a column to its content.
57546 * @param {Number} colIndex
57547 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
57549 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
57550 if(this.cm.isHidden(colIndex)){
57551 return; // can't calc a hidden column
57554 var cid = this.cm.getColumnId(colIndex);
57555 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
57556 if(this.grid.autoSizeHeaders){
57557 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
57560 var newWidth = this.calcColumnWidth(colIndex);
57561 this.cm.setColumnWidth(colIndex,
57562 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
57563 if(!suppressEvent){
57564 this.grid.fireEvent("columnresize", colIndex, newWidth);
57569 * Autofits all columns to their content and then expands to fit any extra space in the grid
57571 autoSizeColumns : function(){
57572 var cm = this.grid.colModel;
57573 var colCount = cm.getColumnCount();
57574 for(var i = 0; i < colCount; i++){
57575 this.autoSizeColumn(i, true, true);
57577 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
57580 this.updateColumns();
57586 * Autofits all columns to the grid's width proportionate with their current size
57587 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
57589 fitColumns : function(reserveScrollSpace){
57590 var cm = this.grid.colModel;
57591 var colCount = cm.getColumnCount();
57595 for (i = 0; i < colCount; i++){
57596 if(!cm.isHidden(i) && !cm.isFixed(i)){
57597 w = cm.getColumnWidth(i);
57603 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
57604 if(reserveScrollSpace){
57607 var frac = (avail - cm.getTotalWidth())/width;
57608 while (cols.length){
57611 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
57613 this.updateColumns();
57617 onRowSelect : function(rowIndex){
57618 var row = this.getRowComposite(rowIndex);
57619 row.addClass("x-grid-row-selected");
57622 onRowDeselect : function(rowIndex){
57623 var row = this.getRowComposite(rowIndex);
57624 row.removeClass("x-grid-row-selected");
57627 onCellSelect : function(row, col){
57628 var cell = this.getCell(row, col);
57630 Roo.fly(cell).addClass("x-grid-cell-selected");
57634 onCellDeselect : function(row, col){
57635 var cell = this.getCell(row, col);
57637 Roo.fly(cell).removeClass("x-grid-cell-selected");
57641 updateHeaderSortState : function(){
57643 // sort state can be single { field: xxx, direction : yyy}
57644 // or { xxx=>ASC , yyy : DESC ..... }
57647 if (!this.ds.multiSort) {
57648 var state = this.ds.getSortState();
57652 mstate[state.field] = state.direction;
57653 // FIXME... - this is not used here.. but might be elsewhere..
57654 this.sortState = state;
57657 mstate = this.ds.sortToggle;
57659 //remove existing sort classes..
57661 var sc = this.sortClasses;
57662 var hds = this.el.select(this.headerSelector).removeClass(sc);
57664 for(var f in mstate) {
57666 var sortColumn = this.cm.findColumnIndex(f);
57668 if(sortColumn != -1){
57669 var sortDir = mstate[f];
57670 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
57679 handleHeaderClick : function(g, index,e){
57681 Roo.log("header click");
57684 // touch events on header are handled by context
57685 this.handleHdCtx(g,index,e);
57690 if(this.headersDisabled){
57693 var dm = g.dataSource, cm = g.colModel;
57694 if(!cm.isSortable(index)){
57699 if (dm.multiSort) {
57700 // update the sortOrder
57702 for(var i = 0; i < cm.config.length; i++ ) {
57704 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
57705 continue; // dont' bother, it's not in sort list or being set.
57708 so.push(cm.config[i].dataIndex);
57714 dm.sort(cm.getDataIndex(index));
57718 destroy : function(){
57720 this.colMenu.removeAll();
57721 Roo.menu.MenuMgr.unregister(this.colMenu);
57722 this.colMenu.getEl().remove();
57723 delete this.colMenu;
57726 this.hmenu.removeAll();
57727 Roo.menu.MenuMgr.unregister(this.hmenu);
57728 this.hmenu.getEl().remove();
57731 if(this.grid.enableColumnMove){
57732 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
57734 for(var dd in dds){
57735 if(!dds[dd].config.isTarget && dds[dd].dragElId){
57736 var elid = dds[dd].dragElId;
57738 Roo.get(elid).remove();
57739 } else if(dds[dd].config.isTarget){
57740 dds[dd].proxyTop.remove();
57741 dds[dd].proxyBottom.remove();
57744 if(Roo.dd.DDM.locationCache[dd]){
57745 delete Roo.dd.DDM.locationCache[dd];
57748 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
57751 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
57752 this.bind(null, null);
57753 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
57756 handleLockChange : function(){
57757 this.refresh(true);
57760 onDenyColumnLock : function(){
57764 onDenyColumnHide : function(){
57768 handleHdMenuClick : function(item){
57769 var index = this.hdCtxIndex;
57770 var cm = this.cm, ds = this.ds;
57773 ds.sort(cm.getDataIndex(index), "ASC");
57776 ds.sort(cm.getDataIndex(index), "DESC");
57779 var lc = cm.getLockedCount();
57780 if(cm.getColumnCount(true) <= lc+1){
57781 this.onDenyColumnLock();
57785 cm.setLocked(index, true, true);
57786 cm.moveColumn(index, lc);
57787 this.grid.fireEvent("columnmove", index, lc);
57789 cm.setLocked(index, true);
57793 var lc = cm.getLockedCount();
57794 if((lc-1) != index){
57795 cm.setLocked(index, false, true);
57796 cm.moveColumn(index, lc-1);
57797 this.grid.fireEvent("columnmove", index, lc-1);
57799 cm.setLocked(index, false);
57802 case 'wider': // used to expand cols on touch..
57804 var cw = cm.getColumnWidth(index);
57805 cw += (item.id == 'wider' ? 1 : -1) * 50;
57806 cw = Math.max(0, cw);
57807 cw = Math.min(cw,4000);
57808 cm.setColumnWidth(index, cw);
57812 index = cm.getIndexById(item.id.substr(4));
57814 if(item.checked && cm.getColumnCount(true) <= 1){
57815 this.onDenyColumnHide();
57818 cm.setHidden(index, item.checked);
57824 beforeColMenuShow : function(){
57825 var cm = this.cm, colCount = cm.getColumnCount();
57826 this.colMenu.removeAll();
57827 for(var i = 0; i < colCount; i++){
57828 this.colMenu.add(new Roo.menu.CheckItem({
57829 id: "col-"+cm.getColumnId(i),
57830 text: cm.getColumnHeader(i),
57831 checked: !cm.isHidden(i),
57837 handleHdCtx : function(g, index, e){
57839 var hd = this.getHeaderCell(index);
57840 this.hdCtxIndex = index;
57841 var ms = this.hmenu.items, cm = this.cm;
57842 ms.get("asc").setDisabled(!cm.isSortable(index));
57843 ms.get("desc").setDisabled(!cm.isSortable(index));
57844 if(this.grid.enableColLock !== false){
57845 ms.get("lock").setDisabled(cm.isLocked(index));
57846 ms.get("unlock").setDisabled(!cm.isLocked(index));
57848 this.hmenu.show(hd, "tl-bl");
57851 handleHdOver : function(e){
57852 var hd = this.findHeaderCell(e.getTarget());
57853 if(hd && !this.headersDisabled){
57854 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
57855 this.fly(hd).addClass("x-grid-hd-over");
57860 handleHdOut : function(e){
57861 var hd = this.findHeaderCell(e.getTarget());
57863 this.fly(hd).removeClass("x-grid-hd-over");
57867 handleSplitDblClick : function(e, t){
57868 var i = this.getCellIndex(t);
57869 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
57870 this.autoSizeColumn(i, true);
57875 render : function(){
57878 var colCount = cm.getColumnCount();
57880 if(this.grid.monitorWindowResize === true){
57881 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
57883 var header = this.renderHeaders();
57884 var body = this.templates.body.apply({rows:""});
57885 var html = this.templates.master.apply({
57888 lockedHeader: header[0],
57892 //this.updateColumns();
57894 this.grid.getGridEl().dom.innerHTML = html;
57896 this.initElements();
57898 // a kludge to fix the random scolling effect in webkit
57899 this.el.on("scroll", function() {
57900 this.el.dom.scrollTop=0; // hopefully not recursive..
57903 this.scroller.on("scroll", this.handleScroll, this);
57904 this.lockedBody.on("mousewheel", this.handleWheel, this);
57905 this.mainBody.on("mousewheel", this.handleWheel, this);
57907 this.mainHd.on("mouseover", this.handleHdOver, this);
57908 this.mainHd.on("mouseout", this.handleHdOut, this);
57909 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
57910 {delegate: "."+this.splitClass});
57912 this.lockedHd.on("mouseover", this.handleHdOver, this);
57913 this.lockedHd.on("mouseout", this.handleHdOut, this);
57914 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
57915 {delegate: "."+this.splitClass});
57917 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
57918 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
57921 this.updateSplitters();
57923 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
57924 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
57925 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
57928 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
57929 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
57931 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
57932 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
57934 if(this.grid.enableColLock !== false){
57935 this.hmenu.add('-',
57936 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
57937 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
57941 this.hmenu.add('-',
57942 {id:"wider", text: this.columnsWiderText},
57943 {id:"narrow", text: this.columnsNarrowText }
57949 if(this.grid.enableColumnHide !== false){
57951 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
57952 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
57953 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
57955 this.hmenu.add('-',
57956 {id:"columns", text: this.columnsText, menu: this.colMenu}
57959 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
57961 this.grid.on("headercontextmenu", this.handleHdCtx, this);
57964 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
57965 this.dd = new Roo.grid.GridDragZone(this.grid, {
57966 ddGroup : this.grid.ddGroup || 'GridDD'
57972 for(var i = 0; i < colCount; i++){
57973 if(cm.isHidden(i)){
57974 this.hideColumn(i);
57976 if(cm.config[i].align){
57977 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
57978 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
57982 this.updateHeaderSortState();
57984 this.beforeInitialResize();
57987 // two part rendering gives faster view to the user
57988 this.renderPhase2.defer(1, this);
57991 renderPhase2 : function(){
57992 // render the rows now
57994 if(this.grid.autoSizeColumns){
57995 this.autoSizeColumns();
57999 beforeInitialResize : function(){
58003 onColumnSplitterMoved : function(i, w){
58004 this.userResized = true;
58005 var cm = this.grid.colModel;
58006 cm.setColumnWidth(i, w, true);
58007 var cid = cm.getColumnId(i);
58008 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
58009 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
58010 this.updateSplitters();
58012 this.grid.fireEvent("columnresize", i, w);
58015 syncRowHeights : function(startIndex, endIndex){
58016 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
58017 startIndex = startIndex || 0;
58018 var mrows = this.getBodyTable().rows;
58019 var lrows = this.getLockedTable().rows;
58020 var len = mrows.length-1;
58021 endIndex = Math.min(endIndex || len, len);
58022 for(var i = startIndex; i <= endIndex; i++){
58023 var m = mrows[i], l = lrows[i];
58024 var h = Math.max(m.offsetHeight, l.offsetHeight);
58025 m.style.height = l.style.height = h + "px";
58030 layout : function(initialRender, is2ndPass)
58033 var auto = g.autoHeight;
58034 var scrollOffset = 16;
58035 var c = g.getGridEl(), cm = this.cm,
58036 expandCol = g.autoExpandColumn,
58038 //c.beginMeasure();
58040 if(!c.dom.offsetWidth){ // display:none?
58042 this.lockedWrap.show();
58043 this.mainWrap.show();
58048 var hasLock = this.cm.isLocked(0);
58050 var tbh = this.headerPanel.getHeight();
58051 var bbh = this.footerPanel.getHeight();
58054 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
58055 var newHeight = ch + c.getBorderWidth("tb");
58057 newHeight = Math.min(g.maxHeight, newHeight);
58059 c.setHeight(newHeight);
58063 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
58066 var s = this.scroller;
58068 var csize = c.getSize(true);
58070 this.el.setSize(csize.width, csize.height);
58072 this.headerPanel.setWidth(csize.width);
58073 this.footerPanel.setWidth(csize.width);
58075 var hdHeight = this.mainHd.getHeight();
58076 var vw = csize.width;
58077 var vh = csize.height - (tbh + bbh);
58081 var bt = this.getBodyTable();
58083 if(cm.getLockedCount() == cm.config.length){
58084 bt = this.getLockedTable();
58087 var ltWidth = hasLock ?
58088 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
58090 var scrollHeight = bt.offsetHeight;
58091 var scrollWidth = ltWidth + bt.offsetWidth;
58092 var vscroll = false, hscroll = false;
58094 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
58096 var lw = this.lockedWrap, mw = this.mainWrap;
58097 var lb = this.lockedBody, mb = this.mainBody;
58099 setTimeout(function(){
58100 var t = s.dom.offsetTop;
58101 var w = s.dom.clientWidth,
58102 h = s.dom.clientHeight;
58105 lw.setSize(ltWidth, h);
58107 mw.setLeftTop(ltWidth, t);
58108 mw.setSize(w-ltWidth, h);
58110 lb.setHeight(h-hdHeight);
58111 mb.setHeight(h-hdHeight);
58113 if(is2ndPass !== true && !gv.userResized && expandCol){
58114 // high speed resize without full column calculation
58116 var ci = cm.getIndexById(expandCol);
58118 ci = cm.findColumnIndex(expandCol);
58120 ci = Math.max(0, ci); // make sure it's got at least the first col.
58121 var expandId = cm.getColumnId(ci);
58122 var tw = cm.getTotalWidth(false);
58123 var currentWidth = cm.getColumnWidth(ci);
58124 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
58125 if(currentWidth != cw){
58126 cm.setColumnWidth(ci, cw, true);
58127 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
58128 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
58129 gv.updateSplitters();
58130 gv.layout(false, true);
58142 onWindowResize : function(){
58143 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
58149 appendFooter : function(parentEl){
58153 sortAscText : "Sort Ascending",
58154 sortDescText : "Sort Descending",
58155 lockText : "Lock Column",
58156 unlockText : "Unlock Column",
58157 columnsText : "Columns",
58159 columnsWiderText : "Wider",
58160 columnsNarrowText : "Thinner"
58164 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
58165 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
58166 this.proxy.el.addClass('x-grid3-col-dd');
58169 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
58170 handleMouseDown : function(e){
58174 callHandleMouseDown : function(e){
58175 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
58180 * Ext JS Library 1.1.1
58181 * Copyright(c) 2006-2007, Ext JS, LLC.
58183 * Originally Released Under LGPL - original licence link has changed is not relivant.
58186 * <script type="text/javascript">
58189 * @extends Roo.dd.DDProxy
58190 * @class Roo.grid.SplitDragZone
58191 * Support for Column Header resizing
58193 * @param {Object} config
58196 // This is a support class used internally by the Grid components
58197 Roo.grid.SplitDragZone = function(grid, hd, hd2){
58199 this.view = grid.getView();
58200 this.proxy = this.view.resizeProxy;
58201 Roo.grid.SplitDragZone.superclass.constructor.call(
58204 "gridSplitters" + this.grid.getGridEl().id, // SGROUP
58206 dragElId : Roo.id(this.proxy.dom),
58211 this.setHandleElId(Roo.id(hd));
58212 if (hd2 !== false) {
58213 this.setOuterHandleElId(Roo.id(hd2));
58216 this.scroll = false;
58218 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
58219 fly: Roo.Element.fly,
58221 b4StartDrag : function(x, y){
58222 this.view.headersDisabled = true;
58223 var h = this.view.mainWrap ? this.view.mainWrap.getHeight() : (
58224 this.view.headEl.getHeight() + this.view.bodyEl.getHeight()
58226 this.proxy.setHeight(h);
58228 // for old system colWidth really stored the actual width?
58229 // in bootstrap we tried using xs/ms/etc.. to do % sizing?
58230 // which in reality did not work.. - it worked only for fixed sizes
58231 // for resizable we need to use actual sizes.
58232 var w = this.cm.getColumnWidth(this.cellIndex);
58233 if (!this.view.mainWrap) {
58235 w = this.view.getHeaderIndex(this.cellIndex).getWidth();
58240 // this was w-this.grid.minColumnWidth;
58241 // doesnt really make sense? - w = thie curren width or the rendered one?
58242 var minw = Math.max(w-this.grid.minColumnWidth, 0);
58243 this.resetConstraints();
58244 this.setXConstraint(minw, 1000);
58245 this.setYConstraint(0, 0);
58246 this.minX = x - minw;
58247 this.maxX = x + 1000;
58249 if (!this.view.mainWrap) { // this is Bootstrap code..
58250 this.getDragEl().style.display='block';
58253 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
58257 handleMouseDown : function(e){
58258 ev = Roo.EventObject.setEvent(e);
58259 var t = this.fly(ev.getTarget());
58260 if(t.hasClass("x-grid-split")){
58261 this.cellIndex = this.view.getCellIndex(t.dom);
58262 this.split = t.dom;
58263 this.cm = this.grid.colModel;
58264 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
58265 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
58270 endDrag : function(e){
58271 this.view.headersDisabled = false;
58272 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
58273 var diff = endX - this.startPos;
58275 var w = this.cm.getColumnWidth(this.cellIndex);
58276 if (!this.view.mainWrap) {
58279 this.view.onColumnSplitterMoved(this.cellIndex, w+diff);
58282 autoOffset : function(){
58283 this.setDelta(0,0);
58287 * Ext JS Library 1.1.1
58288 * Copyright(c) 2006-2007, Ext JS, LLC.
58290 * Originally Released Under LGPL - original licence link has changed is not relivant.
58293 * <script type="text/javascript">
58297 // This is a support class used internally by the Grid components
58298 Roo.grid.GridDragZone = function(grid, config){
58299 this.view = grid.getView();
58300 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
58301 if(this.view.lockedBody){
58302 this.setHandleElId(Roo.id(this.view.mainBody.dom));
58303 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
58305 this.scroll = false;
58307 this.ddel = document.createElement('div');
58308 this.ddel.className = 'x-grid-dd-wrap';
58311 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
58312 ddGroup : "GridDD",
58314 getDragData : function(e){
58315 var t = Roo.lib.Event.getTarget(e);
58316 var rowIndex = this.view.findRowIndex(t);
58317 var sm = this.grid.selModel;
58319 //Roo.log(rowIndex);
58321 if (sm.getSelectedCell) {
58322 // cell selection..
58323 if (!sm.getSelectedCell()) {
58326 if (rowIndex != sm.getSelectedCell()[0]) {
58331 if (sm.getSelections && sm.getSelections().length < 1) {
58336 // before it used to all dragging of unseleted... - now we dont do that.
58337 if(rowIndex !== false){
58342 //Roo.log([ sm.getSelectedCell() ? sm.getSelectedCell()[0] : 'NO' , rowIndex ]);
58344 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
58347 if (e.hasModifier()){
58348 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
58351 Roo.log("getDragData");
58356 rowIndex: rowIndex,
58357 selections: sm.getSelections ? sm.getSelections() : (
58358 sm.getSelectedCell() ? [ this.grid.ds.getAt(sm.getSelectedCell()[0]) ] : [])
58365 onInitDrag : function(e){
58366 var data = this.dragData;
58367 this.ddel.innerHTML = this.grid.getDragDropText();
58368 this.proxy.update(this.ddel);
58369 // fire start drag?
58372 afterRepair : function(){
58373 this.dragging = false;
58376 getRepairXY : function(e, data){
58380 onEndDrag : function(data, e){
58384 onValidDrop : function(dd, e, id){
58389 beforeInvalidDrop : function(e, id){
58394 * Ext JS Library 1.1.1
58395 * Copyright(c) 2006-2007, Ext JS, LLC.
58397 * Originally Released Under LGPL - original licence link has changed is not relivant.
58400 * <script type="text/javascript">
58405 * @class Roo.grid.ColumnModel
58406 * @extends Roo.util.Observable
58407 * This is the default implementation of a ColumnModel used by the Grid. It defines
58408 * the columns in the grid.
58411 var colModel = new Roo.grid.ColumnModel([
58412 {header: "Ticker", width: 60, sortable: true, locked: true},
58413 {header: "Company Name", width: 150, sortable: true},
58414 {header: "Market Cap.", width: 100, sortable: true},
58415 {header: "$ Sales", width: 100, sortable: true, renderer: money},
58416 {header: "Employees", width: 100, sortable: true, resizable: false}
58421 * The config options listed for this class are options which may appear in each
58422 * individual column definition.
58423 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
58425 * @param {Object} config An Array of column config objects. See this class's
58426 * config objects for details.
58428 Roo.grid.ColumnModel = function(config){
58430 * The config passed into the constructor
58432 this.config = []; //config;
58435 // if no id, create one
58436 // if the column does not have a dataIndex mapping,
58437 // map it to the order it is in the config
58438 for(var i = 0, len = config.length; i < len; i++){
58439 this.addColumn(config[i]);
58444 * The width of columns which have no width specified (defaults to 100)
58447 this.defaultWidth = 100;
58450 * Default sortable of columns which have no sortable specified (defaults to false)
58453 this.defaultSortable = false;
58457 * @event widthchange
58458 * Fires when the width of a column changes.
58459 * @param {ColumnModel} this
58460 * @param {Number} columnIndex The column index
58461 * @param {Number} newWidth The new width
58463 "widthchange": true,
58465 * @event headerchange
58466 * Fires when the text of a header changes.
58467 * @param {ColumnModel} this
58468 * @param {Number} columnIndex The column index
58469 * @param {Number} newText The new header text
58471 "headerchange": true,
58473 * @event hiddenchange
58474 * Fires when a column is hidden or "unhidden".
58475 * @param {ColumnModel} this
58476 * @param {Number} columnIndex The column index
58477 * @param {Boolean} hidden true if hidden, false otherwise
58479 "hiddenchange": true,
58481 * @event columnmoved
58482 * Fires when a column is moved.
58483 * @param {ColumnModel} this
58484 * @param {Number} oldIndex
58485 * @param {Number} newIndex
58487 "columnmoved" : true,
58489 * @event columlockchange
58490 * Fires when a column's locked state is changed
58491 * @param {ColumnModel} this
58492 * @param {Number} colIndex
58493 * @param {Boolean} locked true if locked
58495 "columnlockchange" : true
58497 Roo.grid.ColumnModel.superclass.constructor.call(this);
58499 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
58501 * @cfg {String} header The header text to display in the Grid view.
58504 * @cfg {String} xsHeader Header at Bootsrap Extra Small width (default for all)
58507 * @cfg {String} smHeader Header at Bootsrap Small width
58510 * @cfg {String} mdHeader Header at Bootsrap Medium width
58513 * @cfg {String} lgHeader Header at Bootsrap Large width
58516 * @cfg {String} xlHeader Header at Bootsrap extra Large width
58519 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
58520 * {@link Roo.data.Record} definition from which to draw the column's value. If not
58521 * specified, the column's index is used as an index into the Record's data Array.
58524 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
58525 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
58528 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
58529 * Defaults to the value of the {@link #defaultSortable} property.
58530 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
58533 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
58536 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
58539 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
58542 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
58545 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
58546 * given the cell's data value. See {@link #setRenderer}. If not specified, the
58547 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
58548 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
58551 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
58554 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
58557 * @cfg {String} valign (Optional) Set the CSS vertical-align property of the column (eg. middle, top, bottom etc). Defaults to undefined.
58560 * @cfg {String} cursor (Optional)
58563 * @cfg {String} tooltip (Optional)
58566 * @cfg {Number} xs (Optional) can be '0' for hidden at this size (number less than 12)
58569 * @cfg {Number} sm (Optional) can be '0' for hidden at this size (number less than 12)
58572 * @cfg {Number} md (Optional) can be '0' for hidden at this size (number less than 12)
58575 * @cfg {Number} lg (Optional) can be '0' for hidden at this size (number less than 12)
58578 * @cfg {Number} xl (Optional) can be '0' for hidden at this size (number less than 12)
58581 * Returns the id of the column at the specified index.
58582 * @param {Number} index The column index
58583 * @return {String} the id
58585 getColumnId : function(index){
58586 return this.config[index].id;
58590 * Returns the column for a specified id.
58591 * @param {String} id The column id
58592 * @return {Object} the column
58594 getColumnById : function(id){
58595 return this.lookup[id];
58600 * Returns the column Object for a specified dataIndex.
58601 * @param {String} dataIndex The column dataIndex
58602 * @return {Object|Boolean} the column or false if not found
58604 getColumnByDataIndex: function(dataIndex){
58605 var index = this.findColumnIndex(dataIndex);
58606 return index > -1 ? this.config[index] : false;
58610 * Returns the index for a specified column id.
58611 * @param {String} id The column id
58612 * @return {Number} the index, or -1 if not found
58614 getIndexById : function(id){
58615 for(var i = 0, len = this.config.length; i < len; i++){
58616 if(this.config[i].id == id){
58624 * Returns the index for a specified column dataIndex.
58625 * @param {String} dataIndex The column dataIndex
58626 * @return {Number} the index, or -1 if not found
58629 findColumnIndex : function(dataIndex){
58630 for(var i = 0, len = this.config.length; i < len; i++){
58631 if(this.config[i].dataIndex == dataIndex){
58639 moveColumn : function(oldIndex, newIndex){
58640 var c = this.config[oldIndex];
58641 this.config.splice(oldIndex, 1);
58642 this.config.splice(newIndex, 0, c);
58643 this.dataMap = null;
58644 this.fireEvent("columnmoved", this, oldIndex, newIndex);
58647 isLocked : function(colIndex){
58648 return this.config[colIndex].locked === true;
58651 setLocked : function(colIndex, value, suppressEvent){
58652 if(this.isLocked(colIndex) == value){
58655 this.config[colIndex].locked = value;
58656 if(!suppressEvent){
58657 this.fireEvent("columnlockchange", this, colIndex, value);
58661 getTotalLockedWidth : function(){
58662 var totalWidth = 0;
58663 for(var i = 0; i < this.config.length; i++){
58664 if(this.isLocked(i) && !this.isHidden(i)){
58665 this.totalWidth += this.getColumnWidth(i);
58671 getLockedCount : function(){
58672 for(var i = 0, len = this.config.length; i < len; i++){
58673 if(!this.isLocked(i)){
58678 return this.config.length;
58682 * Returns the number of columns.
58685 getColumnCount : function(visibleOnly){
58686 if(visibleOnly === true){
58688 for(var i = 0, len = this.config.length; i < len; i++){
58689 if(!this.isHidden(i)){
58695 return this.config.length;
58699 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
58700 * @param {Function} fn
58701 * @param {Object} scope (optional)
58702 * @return {Array} result
58704 getColumnsBy : function(fn, scope){
58706 for(var i = 0, len = this.config.length; i < len; i++){
58707 var c = this.config[i];
58708 if(fn.call(scope||this, c, i) === true){
58716 * Returns true if the specified column is sortable.
58717 * @param {Number} col The column index
58718 * @return {Boolean}
58720 isSortable : function(col){
58721 if(typeof this.config[col].sortable == "undefined"){
58722 return this.defaultSortable;
58724 return this.config[col].sortable;
58728 * Returns the rendering (formatting) function defined for the column.
58729 * @param {Number} col The column index.
58730 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
58732 getRenderer : function(col){
58733 if(!this.config[col].renderer){
58734 return Roo.grid.ColumnModel.defaultRenderer;
58736 return this.config[col].renderer;
58740 * Sets the rendering (formatting) function for a column.
58741 * @param {Number} col The column index
58742 * @param {Function} fn The function to use to process the cell's raw data
58743 * to return HTML markup for the grid view. The render function is called with
58744 * the following parameters:<ul>
58745 * <li>Data value.</li>
58746 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
58747 * <li>css A CSS style string to apply to the table cell.</li>
58748 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
58749 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
58750 * <li>Row index</li>
58751 * <li>Column index</li>
58752 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
58754 setRenderer : function(col, fn){
58755 this.config[col].renderer = fn;
58759 * Returns the width for the specified column.
58760 * @param {Number} col The column index
58761 * @param (optional) {String} gridSize bootstrap width size.
58764 getColumnWidth : function(col, gridSize)
58766 var cfg = this.config[col];
58768 if (typeof(gridSize) == 'undefined') {
58769 return cfg.width * 1 || this.defaultWidth;
58771 if (gridSize === false) { // if we set it..
58772 return cfg.width || false;
58774 var sizes = ['xl', 'lg', 'md', 'sm', 'xs'];
58776 for(var i = sizes.indexOf(gridSize); i < sizes.length; i++) {
58777 if (typeof(cfg[ sizes[i] ] ) == 'undefined') {
58780 return cfg[ sizes[i] ];
58787 * Sets the width for a column.
58788 * @param {Number} col The column index
58789 * @param {Number} width The new width
58791 setColumnWidth : function(col, width, suppressEvent){
58792 this.config[col].width = width;
58793 this.totalWidth = null;
58794 if(!suppressEvent){
58795 this.fireEvent("widthchange", this, col, width);
58800 * Returns the total width of all columns.
58801 * @param {Boolean} includeHidden True to include hidden column widths
58804 getTotalWidth : function(includeHidden){
58805 if(!this.totalWidth){
58806 this.totalWidth = 0;
58807 for(var i = 0, len = this.config.length; i < len; i++){
58808 if(includeHidden || !this.isHidden(i)){
58809 this.totalWidth += this.getColumnWidth(i);
58813 return this.totalWidth;
58817 * Returns the header for the specified column.
58818 * @param {Number} col The column index
58821 getColumnHeader : function(col){
58822 return this.config[col].header;
58826 * Sets the header for a column.
58827 * @param {Number} col The column index
58828 * @param {String} header The new header
58830 setColumnHeader : function(col, header){
58831 this.config[col].header = header;
58832 this.fireEvent("headerchange", this, col, header);
58836 * Returns the tooltip for the specified column.
58837 * @param {Number} col The column index
58840 getColumnTooltip : function(col){
58841 return this.config[col].tooltip;
58844 * Sets the tooltip for a column.
58845 * @param {Number} col The column index
58846 * @param {String} tooltip The new tooltip
58848 setColumnTooltip : function(col, tooltip){
58849 this.config[col].tooltip = tooltip;
58853 * Returns the dataIndex for the specified column.
58854 * @param {Number} col The column index
58857 getDataIndex : function(col){
58858 return this.config[col].dataIndex;
58862 * Sets the dataIndex for a column.
58863 * @param {Number} col The column index
58864 * @param {Number} dataIndex The new dataIndex
58866 setDataIndex : function(col, dataIndex){
58867 this.config[col].dataIndex = dataIndex;
58873 * Returns true if the cell is editable.
58874 * @param {Number} colIndex The column index
58875 * @param {Number} rowIndex The row index - this is nto actually used..?
58876 * @return {Boolean}
58878 isCellEditable : function(colIndex, rowIndex){
58879 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
58883 * Returns the editor defined for the cell/column.
58884 * return false or null to disable editing.
58885 * @param {Number} colIndex The column index
58886 * @param {Number} rowIndex The row index
58889 getCellEditor : function(colIndex, rowIndex){
58890 return this.config[colIndex].editor;
58894 * Sets if a column is editable.
58895 * @param {Number} col The column index
58896 * @param {Boolean} editable True if the column is editable
58898 setEditable : function(col, editable){
58899 this.config[col].editable = editable;
58904 * Returns true if the column is hidden.
58905 * @param {Number} colIndex The column index
58906 * @return {Boolean}
58908 isHidden : function(colIndex){
58909 return this.config[colIndex].hidden;
58914 * Returns true if the column width cannot be changed
58916 isFixed : function(colIndex){
58917 return this.config[colIndex].fixed;
58921 * Returns true if the column can be resized
58922 * @return {Boolean}
58924 isResizable : function(colIndex){
58925 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
58928 * Sets if a column is hidden.
58929 * @param {Number} colIndex The column index
58930 * @param {Boolean} hidden True if the column is hidden
58932 setHidden : function(colIndex, hidden){
58933 this.config[colIndex].hidden = hidden;
58934 this.totalWidth = null;
58935 this.fireEvent("hiddenchange", this, colIndex, hidden);
58939 * Sets the editor for a column.
58940 * @param {Number} col The column index
58941 * @param {Object} editor The editor object
58943 setEditor : function(col, editor){
58944 this.config[col].editor = editor;
58947 * Add a column (experimental...) - defaults to adding to the end..
58948 * @param {Object} config
58950 addColumn : function(c)
58953 var i = this.config.length;
58954 this.config[i] = c;
58956 if(typeof c.dataIndex == "undefined"){
58959 if(typeof c.renderer == "string"){
58960 c.renderer = Roo.util.Format[c.renderer];
58962 if(typeof c.id == "undefined"){
58965 if(c.editor && c.editor.xtype){
58966 c.editor = Roo.factory(c.editor, Roo.grid);
58968 if(c.editor && c.editor.isFormField){
58969 c.editor = new Roo.grid.GridEditor(c.editor);
58971 this.lookup[c.id] = c;
58976 Roo.grid.ColumnModel.defaultRenderer = function(value)
58978 if(typeof value == "object") {
58981 if(typeof value == "string" && value.length < 1){
58985 return String.format("{0}", value);
58988 // Alias for backwards compatibility
58989 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
58992 * Ext JS Library 1.1.1
58993 * Copyright(c) 2006-2007, Ext JS, LLC.
58995 * Originally Released Under LGPL - original licence link has changed is not relivant.
58998 * <script type="text/javascript">
59002 * @class Roo.grid.AbstractSelectionModel
59003 * @extends Roo.util.Observable
59005 * Abstract base class for grid SelectionModels. It provides the interface that should be
59006 * implemented by descendant classes. This class should not be directly instantiated.
59009 Roo.grid.AbstractSelectionModel = function(){
59010 this.locked = false;
59011 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
59014 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
59015 /** @ignore Called by the grid automatically. Do not call directly. */
59016 init : function(grid){
59022 * Locks the selections.
59025 this.locked = true;
59029 * Unlocks the selections.
59031 unlock : function(){
59032 this.locked = false;
59036 * Returns true if the selections are locked.
59037 * @return {Boolean}
59039 isLocked : function(){
59040 return this.locked;
59044 * Ext JS Library 1.1.1
59045 * Copyright(c) 2006-2007, Ext JS, LLC.
59047 * Originally Released Under LGPL - original licence link has changed is not relivant.
59050 * <script type="text/javascript">
59053 * @extends Roo.grid.AbstractSelectionModel
59054 * @class Roo.grid.RowSelectionModel
59055 * The default SelectionModel used by {@link Roo.grid.Grid}.
59056 * It supports multiple selections and keyboard selection/navigation.
59058 * @param {Object} config
59060 Roo.grid.RowSelectionModel = function(config){
59061 Roo.apply(this, config);
59062 this.selections = new Roo.util.MixedCollection(false, function(o){
59067 this.lastActive = false;
59071 * @event selectionchange
59072 * Fires when the selection changes
59073 * @param {SelectionModel} this
59075 "selectionchange" : true,
59077 * @event afterselectionchange
59078 * Fires after the selection changes (eg. by key press or clicking)
59079 * @param {SelectionModel} this
59081 "afterselectionchange" : true,
59083 * @event beforerowselect
59084 * Fires when a row is selected being selected, return false to cancel.
59085 * @param {SelectionModel} this
59086 * @param {Number} rowIndex The selected index
59087 * @param {Boolean} keepExisting False if other selections will be cleared
59089 "beforerowselect" : true,
59092 * Fires when a row is selected.
59093 * @param {SelectionModel} this
59094 * @param {Number} rowIndex The selected index
59095 * @param {Roo.data.Record} r The record
59097 "rowselect" : true,
59099 * @event rowdeselect
59100 * Fires when a row is deselected.
59101 * @param {SelectionModel} this
59102 * @param {Number} rowIndex The selected index
59104 "rowdeselect" : true
59106 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
59107 this.locked = false;
59110 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
59112 * @cfg {Boolean} singleSelect
59113 * True to allow selection of only one row at a time (defaults to false)
59115 singleSelect : false,
59118 initEvents : function(){
59120 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
59121 this.grid.on("mousedown", this.handleMouseDown, this);
59122 }else{ // allow click to work like normal
59123 this.grid.on("rowclick", this.handleDragableRowClick, this);
59125 // bootstrap does not have a view..
59126 var view = this.grid.view ? this.grid.view : this.grid;
59127 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
59128 "up" : function(e){
59130 this.selectPrevious(e.shiftKey);
59131 }else if(this.last !== false && this.lastActive !== false){
59132 var last = this.last;
59133 this.selectRange(this.last, this.lastActive-1);
59134 view.focusRow(this.lastActive);
59135 if(last !== false){
59139 this.selectFirstRow();
59141 this.fireEvent("afterselectionchange", this);
59143 "down" : function(e){
59145 this.selectNext(e.shiftKey);
59146 }else if(this.last !== false && this.lastActive !== false){
59147 var last = this.last;
59148 this.selectRange(this.last, this.lastActive+1);
59149 view.focusRow(this.lastActive);
59150 if(last !== false){
59154 this.selectFirstRow();
59156 this.fireEvent("afterselectionchange", this);
59162 view.on("refresh", this.onRefresh, this);
59163 view.on("rowupdated", this.onRowUpdated, this);
59164 view.on("rowremoved", this.onRemove, this);
59168 onRefresh : function(){
59169 var ds = this.grid.ds, i, v = this.grid.view;
59170 var s = this.selections;
59171 s.each(function(r){
59172 if((i = ds.indexOfId(r.id)) != -1){
59174 s.add(ds.getAt(i)); // updating the selection relate data
59182 onRemove : function(v, index, r){
59183 this.selections.remove(r);
59187 onRowUpdated : function(v, index, r){
59188 if(this.isSelected(r)){
59189 v.onRowSelect(index);
59195 * @param {Array} records The records to select
59196 * @param {Boolean} keepExisting (optional) True to keep existing selections
59198 selectRecords : function(records, keepExisting){
59200 this.clearSelections();
59202 var ds = this.grid.ds;
59203 for(var i = 0, len = records.length; i < len; i++){
59204 this.selectRow(ds.indexOf(records[i]), true);
59209 * Gets the number of selected rows.
59212 getCount : function(){
59213 return this.selections.length;
59217 * Selects the first row in the grid.
59219 selectFirstRow : function(){
59224 * Select the last row.
59225 * @param {Boolean} keepExisting (optional) True to keep existing selections
59227 selectLastRow : function(keepExisting){
59228 this.selectRow(this.grid.ds.getCount() - 1, keepExisting);
59232 * Selects the row immediately following the last selected row.
59233 * @param {Boolean} keepExisting (optional) True to keep existing selections
59235 selectNext : function(keepExisting){
59236 if(this.last !== false && (this.last+1) < this.grid.ds.getCount()){
59237 this.selectRow(this.last+1, keepExisting);
59238 var view = this.grid.view ? this.grid.view : this.grid;
59239 view.focusRow(this.last);
59244 * Selects the row that precedes the last selected row.
59245 * @param {Boolean} keepExisting (optional) True to keep existing selections
59247 selectPrevious : function(keepExisting){
59249 this.selectRow(this.last-1, keepExisting);
59250 var view = this.grid.view ? this.grid.view : this.grid;
59251 view.focusRow(this.last);
59256 * Returns the selected records
59257 * @return {Array} Array of selected records
59259 getSelections : function(){
59260 return [].concat(this.selections.items);
59264 * Returns the first selected record.
59267 getSelected : function(){
59268 return this.selections.itemAt(0);
59273 * Clears all selections.
59275 clearSelections : function(fast){
59280 var ds = this.grid.ds;
59281 var s = this.selections;
59282 s.each(function(r){
59283 this.deselectRow(ds.indexOfId(r.id));
59287 this.selections.clear();
59294 * Selects all rows.
59296 selectAll : function(){
59300 this.selections.clear();
59301 for(var i = 0, len = this.grid.ds.getCount(); i < len; i++){
59302 this.selectRow(i, true);
59307 * Returns True if there is a selection.
59308 * @return {Boolean}
59310 hasSelection : function(){
59311 return this.selections.length > 0;
59315 * Returns True if the specified row is selected.
59316 * @param {Number/Record} record The record or index of the record to check
59317 * @return {Boolean}
59319 isSelected : function(index){
59320 var r = typeof index == "number" ? this.grid.ds.getAt(index) : index;
59321 return (r && this.selections.key(r.id) ? true : false);
59325 * Returns True if the specified record id is selected.
59326 * @param {String} id The id of record to check
59327 * @return {Boolean}
59329 isIdSelected : function(id){
59330 return (this.selections.key(id) ? true : false);
59334 handleMouseDown : function(e, t)
59336 var view = this.grid.view ? this.grid.view : this.grid;
59338 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
59341 if(e.shiftKey && this.last !== false){
59342 var last = this.last;
59343 this.selectRange(last, rowIndex, e.ctrlKey);
59344 this.last = last; // reset the last
59345 view.focusRow(rowIndex);
59347 var isSelected = this.isSelected(rowIndex);
59348 if(e.button !== 0 && isSelected){
59349 view.focusRow(rowIndex);
59350 }else if(e.ctrlKey && isSelected){
59351 this.deselectRow(rowIndex);
59352 }else if(!isSelected){
59353 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
59354 view.focusRow(rowIndex);
59357 this.fireEvent("afterselectionchange", this);
59360 handleDragableRowClick : function(grid, rowIndex, e)
59362 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
59363 this.selectRow(rowIndex, false);
59364 var view = this.grid.view ? this.grid.view : this.grid;
59365 view.focusRow(rowIndex);
59366 this.fireEvent("afterselectionchange", this);
59371 * Selects multiple rows.
59372 * @param {Array} rows Array of the indexes of the row to select
59373 * @param {Boolean} keepExisting (optional) True to keep existing selections
59375 selectRows : function(rows, keepExisting){
59377 this.clearSelections();
59379 for(var i = 0, len = rows.length; i < len; i++){
59380 this.selectRow(rows[i], true);
59385 * Selects a range of rows. All rows in between startRow and endRow are also selected.
59386 * @param {Number} startRow The index of the first row in the range
59387 * @param {Number} endRow The index of the last row in the range
59388 * @param {Boolean} keepExisting (optional) True to retain existing selections
59390 selectRange : function(startRow, endRow, keepExisting){
59395 this.clearSelections();
59397 if(startRow <= endRow){
59398 for(var i = startRow; i <= endRow; i++){
59399 this.selectRow(i, true);
59402 for(var i = startRow; i >= endRow; i--){
59403 this.selectRow(i, true);
59409 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
59410 * @param {Number} startRow The index of the first row in the range
59411 * @param {Number} endRow The index of the last row in the range
59413 deselectRange : function(startRow, endRow, preventViewNotify){
59417 for(var i = startRow; i <= endRow; i++){
59418 this.deselectRow(i, preventViewNotify);
59424 * @param {Number} row The index of the row to select
59425 * @param {Boolean} keepExisting (optional) True to keep existing selections
59427 selectRow : function(index, keepExisting, preventViewNotify){
59428 if(this.locked || (index < 0 || index >= this.grid.ds.getCount())) {
59431 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
59432 if(!keepExisting || this.singleSelect){
59433 this.clearSelections();
59435 var r = this.grid.ds.getAt(index);
59436 this.selections.add(r);
59437 this.last = this.lastActive = index;
59438 if(!preventViewNotify){
59439 var view = this.grid.view ? this.grid.view : this.grid;
59440 view.onRowSelect(index);
59442 this.fireEvent("rowselect", this, index, r);
59443 this.fireEvent("selectionchange", this);
59449 * @param {Number} row The index of the row to deselect
59451 deselectRow : function(index, preventViewNotify){
59455 if(this.last == index){
59458 if(this.lastActive == index){
59459 this.lastActive = false;
59461 var r = this.grid.ds.getAt(index);
59462 this.selections.remove(r);
59463 if(!preventViewNotify){
59464 var view = this.grid.view ? this.grid.view : this.grid;
59465 view.onRowDeselect(index);
59467 this.fireEvent("rowdeselect", this, index);
59468 this.fireEvent("selectionchange", this);
59472 restoreLast : function(){
59474 this.last = this._last;
59479 acceptsNav : function(row, col, cm){
59480 return !cm.isHidden(col) && cm.isCellEditable(col, row);
59484 onEditorKey : function(field, e){
59485 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
59490 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
59492 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
59494 }else if(k == e.ENTER && !e.ctrlKey){
59498 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
59500 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
59502 }else if(k == e.ESC){
59506 g.startEditing(newCell[0], newCell[1]);
59511 * Ext JS Library 1.1.1
59512 * Copyright(c) 2006-2007, Ext JS, LLC.
59514 * Originally Released Under LGPL - original licence link has changed is not relivant.
59517 * <script type="text/javascript">
59520 * @class Roo.grid.CellSelectionModel
59521 * @extends Roo.grid.AbstractSelectionModel
59522 * This class provides the basic implementation for cell selection in a grid.
59524 * @param {Object} config The object containing the configuration of this model.
59525 * @cfg {Boolean} enter_is_tab Enter behaves the same as tab. (eg. goes to next cell) default: false
59527 Roo.grid.CellSelectionModel = function(config){
59528 Roo.apply(this, config);
59530 this.selection = null;
59534 * @event beforerowselect
59535 * Fires before a cell is selected.
59536 * @param {SelectionModel} this
59537 * @param {Number} rowIndex The selected row index
59538 * @param {Number} colIndex The selected cell index
59540 "beforecellselect" : true,
59542 * @event cellselect
59543 * Fires when a cell is selected.
59544 * @param {SelectionModel} this
59545 * @param {Number} rowIndex The selected row index
59546 * @param {Number} colIndex The selected cell index
59548 "cellselect" : true,
59550 * @event selectionchange
59551 * Fires when the active selection changes.
59552 * @param {SelectionModel} this
59553 * @param {Object} selection null for no selection or an object (o) with two properties
59555 <li>o.record: the record object for the row the selection is in</li>
59556 <li>o.cell: An array of [rowIndex, columnIndex]</li>
59559 "selectionchange" : true,
59562 * Fires when the tab (or enter) was pressed on the last editable cell
59563 * You can use this to trigger add new row.
59564 * @param {SelectionModel} this
59568 * @event beforeeditnext
59569 * Fires before the next editable sell is made active
59570 * You can use this to skip to another cell or fire the tabend
59571 * if you set cell to false
59572 * @param {Object} eventdata object : { cell : [ row, col ] }
59574 "beforeeditnext" : true
59576 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
59579 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
59581 enter_is_tab: false,
59584 initEvents : function(){
59585 this.grid.on("mousedown", this.handleMouseDown, this);
59586 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
59587 var view = this.grid.view;
59588 view.on("refresh", this.onViewChange, this);
59589 view.on("rowupdated", this.onRowUpdated, this);
59590 view.on("beforerowremoved", this.clearSelections, this);
59591 view.on("beforerowsinserted", this.clearSelections, this);
59592 if(this.grid.isEditor){
59593 this.grid.on("beforeedit", this.beforeEdit, this);
59598 beforeEdit : function(e){
59599 this.select(e.row, e.column, false, true, e.record);
59603 onRowUpdated : function(v, index, r){
59604 if(this.selection && this.selection.record == r){
59605 v.onCellSelect(index, this.selection.cell[1]);
59610 onViewChange : function(){
59611 this.clearSelections(true);
59615 * Returns the currently selected cell,.
59616 * @return {Array} The selected cell (row, column) or null if none selected.
59618 getSelectedCell : function(){
59619 return this.selection ? this.selection.cell : null;
59623 * Clears all selections.
59624 * @param {Boolean} true to prevent the gridview from being notified about the change.
59626 clearSelections : function(preventNotify){
59627 var s = this.selection;
59629 if(preventNotify !== true){
59630 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
59632 this.selection = null;
59633 this.fireEvent("selectionchange", this, null);
59638 * Returns true if there is a selection.
59639 * @return {Boolean}
59641 hasSelection : function(){
59642 return this.selection ? true : false;
59646 handleMouseDown : function(e, t){
59647 var v = this.grid.getView();
59648 if(this.isLocked()){
59651 var row = v.findRowIndex(t);
59652 var cell = v.findCellIndex(t);
59653 if(row !== false && cell !== false){
59654 this.select(row, cell);
59660 * @param {Number} rowIndex
59661 * @param {Number} collIndex
59663 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
59664 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
59665 this.clearSelections();
59666 r = r || this.grid.dataSource.getAt(rowIndex);
59669 cell : [rowIndex, colIndex]
59671 if(!preventViewNotify){
59672 var v = this.grid.getView();
59673 v.onCellSelect(rowIndex, colIndex);
59674 if(preventFocus !== true){
59675 v.focusCell(rowIndex, colIndex);
59678 this.fireEvent("cellselect", this, rowIndex, colIndex);
59679 this.fireEvent("selectionchange", this, this.selection);
59684 isSelectable : function(rowIndex, colIndex, cm){
59685 return !cm.isHidden(colIndex);
59689 handleKeyDown : function(e){
59690 //Roo.log('Cell Sel Model handleKeyDown');
59691 if(!e.isNavKeyPress()){
59694 var g = this.grid, s = this.selection;
59697 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
59699 this.select(cell[0], cell[1]);
59704 var walk = function(row, col, step){
59705 return g.walkCells(row, col, step, sm.isSelectable, sm);
59707 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
59714 // handled by onEditorKey
59715 if (g.isEditor && g.editing) {
59719 newCell = walk(r, c-1, -1);
59721 newCell = walk(r, c+1, 1);
59726 newCell = walk(r+1, c, 1);
59730 newCell = walk(r-1, c, -1);
59734 newCell = walk(r, c+1, 1);
59738 newCell = walk(r, c-1, -1);
59743 if(g.isEditor && !g.editing){
59744 g.startEditing(r, c);
59753 this.select(newCell[0], newCell[1]);
59759 acceptsNav : function(row, col, cm){
59760 return !cm.isHidden(col) && cm.isCellEditable(col, row);
59764 * @param {Number} field (not used) - as it's normally used as a listener
59765 * @param {Number} e - event - fake it by using
59767 * var e = Roo.EventObjectImpl.prototype;
59768 * e.keyCode = e.TAB
59772 onEditorKey : function(field, e){
59774 var k = e.getKey(),
59777 ed = g.activeEditor,
59779 ///Roo.log('onEditorKey' + k);
59782 if (this.enter_is_tab && k == e.ENTER) {
59788 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
59790 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
59796 } else if(k == e.ENTER && !e.ctrlKey){
59799 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
59801 } else if(k == e.ESC){
59806 var ecall = { cell : newCell, forward : forward };
59807 this.fireEvent('beforeeditnext', ecall );
59808 newCell = ecall.cell;
59809 forward = ecall.forward;
59813 //Roo.log('next cell after edit');
59814 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
59815 } else if (forward) {
59816 // tabbed past last
59817 this.fireEvent.defer(100, this, ['tabend',this]);
59822 * Ext JS Library 1.1.1
59823 * Copyright(c) 2006-2007, Ext JS, LLC.
59825 * Originally Released Under LGPL - original licence link has changed is not relivant.
59828 * <script type="text/javascript">
59832 * @class Roo.grid.EditorGrid
59833 * @extends Roo.grid.Grid
59834 * Class for creating and editable grid.
59835 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
59836 * The container MUST have some type of size defined for the grid to fill. The container will be
59837 * automatically set to position relative if it isn't already.
59838 * @param {Object} dataSource The data model to bind to
59839 * @param {Object} colModel The column model with info about this grid's columns
59841 Roo.grid.EditorGrid = function(container, config){
59842 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
59843 this.getGridEl().addClass("xedit-grid");
59845 if(!this.selModel){
59846 this.selModel = new Roo.grid.CellSelectionModel();
59849 this.activeEditor = null;
59853 * @event beforeedit
59854 * Fires before cell editing is triggered. The edit event object has the following properties <br />
59855 * <ul style="padding:5px;padding-left:16px;">
59856 * <li>grid - This grid</li>
59857 * <li>record - The record being edited</li>
59858 * <li>field - The field name being edited</li>
59859 * <li>value - The value for the field being edited.</li>
59860 * <li>row - The grid row index</li>
59861 * <li>column - The grid column index</li>
59862 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
59864 * @param {Object} e An edit event (see above for description)
59866 "beforeedit" : true,
59869 * Fires after a cell is edited. <br />
59870 * <ul style="padding:5px;padding-left:16px;">
59871 * <li>grid - This grid</li>
59872 * <li>record - The record being edited</li>
59873 * <li>field - The field name being edited</li>
59874 * <li>value - The value being set</li>
59875 * <li>originalValue - The original value for the field, before the edit.</li>
59876 * <li>row - The grid row index</li>
59877 * <li>column - The grid column index</li>
59879 * @param {Object} e An edit event (see above for description)
59881 "afteredit" : true,
59883 * @event validateedit
59884 * Fires after a cell is edited, but before the value is set in the record.
59885 * You can use this to modify the value being set in the field, Return false
59886 * to cancel the change. The edit event object has the following properties <br />
59887 * <ul style="padding:5px;padding-left:16px;">
59888 * <li>editor - This editor</li>
59889 * <li>grid - This grid</li>
59890 * <li>record - The record being edited</li>
59891 * <li>field - The field name being edited</li>
59892 * <li>value - The value being set</li>
59893 * <li>originalValue - The original value for the field, before the edit.</li>
59894 * <li>row - The grid row index</li>
59895 * <li>column - The grid column index</li>
59896 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
59898 * @param {Object} e An edit event (see above for description)
59900 "validateedit" : true
59902 this.on("bodyscroll", this.stopEditing, this);
59903 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
59906 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
59908 * @cfg {Number} clicksToEdit
59909 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
59916 trackMouseOver: false, // causes very odd FF errors
59918 onCellDblClick : function(g, row, col){
59919 this.startEditing(row, col);
59922 onEditComplete : function(ed, value, startValue){
59923 this.editing = false;
59924 this.activeEditor = null;
59925 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
59927 var field = this.colModel.getDataIndex(ed.col);
59932 originalValue: startValue,
59939 var cell = Roo.get(this.view.getCell(ed.row,ed.col));
59942 if(String(value) !== String(startValue)){
59944 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
59945 r.set(field, e.value);
59946 // if we are dealing with a combo box..
59947 // then we also set the 'name' colum to be the displayField
59948 if (ed.field.displayField && ed.field.name) {
59949 r.set(ed.field.name, ed.field.el.dom.value);
59952 delete e.cancel; //?? why!!!
59953 this.fireEvent("afteredit", e);
59956 this.fireEvent("afteredit", e); // always fire it!
59958 this.view.focusCell(ed.row, ed.col);
59962 * Starts editing the specified for the specified row/column
59963 * @param {Number} rowIndex
59964 * @param {Number} colIndex
59966 startEditing : function(row, col){
59967 this.stopEditing();
59968 if(this.colModel.isCellEditable(col, row)){
59969 this.view.ensureVisible(row, col, true);
59971 var r = this.dataSource.getAt(row);
59972 var field = this.colModel.getDataIndex(col);
59973 var cell = Roo.get(this.view.getCell(row,col));
59978 value: r.data[field],
59983 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
59984 this.editing = true;
59985 var ed = this.colModel.getCellEditor(col, row);
59991 ed.render(ed.parentEl || document.body);
59997 (function(){ // complex but required for focus issues in safari, ie and opera
60001 ed.on("complete", this.onEditComplete, this, {single: true});
60002 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
60003 this.activeEditor = ed;
60004 var v = r.data[field];
60005 ed.startEdit(this.view.getCell(row, col), v);
60006 // combo's with 'displayField and name set
60007 if (ed.field.displayField && ed.field.name) {
60008 ed.field.el.dom.value = r.data[ed.field.name];
60012 }).defer(50, this);
60018 * Stops any active editing
60020 stopEditing : function(){
60021 if(this.activeEditor){
60022 this.activeEditor.completeEdit();
60024 this.activeEditor = null;
60028 * Called to get grid's drag proxy text, by default returns this.ddText.
60031 getDragDropText : function(){
60032 var count = this.selModel.getSelectedCell() ? 1 : 0;
60033 return String.format(this.ddText, count, count == 1 ? '' : 's');
60038 * Ext JS Library 1.1.1
60039 * Copyright(c) 2006-2007, Ext JS, LLC.
60041 * Originally Released Under LGPL - original licence link has changed is not relivant.
60044 * <script type="text/javascript">
60047 // private - not really -- you end up using it !
60048 // This is a support class used internally by the Grid components
60051 * @class Roo.grid.GridEditor
60052 * @extends Roo.Editor
60053 * Class for creating and editable grid elements.
60054 * @param {Object} config any settings (must include field)
60056 Roo.grid.GridEditor = function(field, config){
60057 if (!config && field.field) {
60059 field = Roo.factory(config.field, Roo.form);
60061 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
60062 field.monitorTab = false;
60065 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
60068 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
60071 alignment: "tl-tl",
60074 cls: "x-small-editor x-grid-editor",
60079 * Ext JS Library 1.1.1
60080 * Copyright(c) 2006-2007, Ext JS, LLC.
60082 * Originally Released Under LGPL - original licence link has changed is not relivant.
60085 * <script type="text/javascript">
60090 Roo.grid.PropertyRecord = Roo.data.Record.create([
60091 {name:'name',type:'string'}, 'value'
60095 Roo.grid.PropertyStore = function(grid, source){
60097 this.store = new Roo.data.Store({
60098 recordType : Roo.grid.PropertyRecord
60100 this.store.on('update', this.onUpdate, this);
60102 this.setSource(source);
60104 Roo.grid.PropertyStore.superclass.constructor.call(this);
60109 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
60110 setSource : function(o){
60112 this.store.removeAll();
60115 if(this.isEditableValue(o[k])){
60116 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
60119 this.store.loadRecords({records: data}, {}, true);
60122 onUpdate : function(ds, record, type){
60123 if(type == Roo.data.Record.EDIT){
60124 var v = record.data['value'];
60125 var oldValue = record.modified['value'];
60126 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
60127 this.source[record.id] = v;
60129 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
60136 getProperty : function(row){
60137 return this.store.getAt(row);
60140 isEditableValue: function(val){
60141 if(val && val instanceof Date){
60143 }else if(typeof val == 'object' || typeof val == 'function'){
60149 setValue : function(prop, value){
60150 this.source[prop] = value;
60151 this.store.getById(prop).set('value', value);
60154 getSource : function(){
60155 return this.source;
60159 Roo.grid.PropertyColumnModel = function(grid, store){
60162 g.PropertyColumnModel.superclass.constructor.call(this, [
60163 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
60164 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
60166 this.store = store;
60167 this.bselect = Roo.DomHelper.append(document.body, {
60168 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
60169 {tag: 'option', value: 'true', html: 'true'},
60170 {tag: 'option', value: 'false', html: 'false'}
60173 Roo.id(this.bselect);
60176 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
60177 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
60178 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
60179 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
60180 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
60182 this.renderCellDelegate = this.renderCell.createDelegate(this);
60183 this.renderPropDelegate = this.renderProp.createDelegate(this);
60186 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
60190 valueText : 'Value',
60192 dateFormat : 'm/j/Y',
60195 renderDate : function(dateVal){
60196 return dateVal.dateFormat(this.dateFormat);
60199 renderBool : function(bVal){
60200 return bVal ? 'true' : 'false';
60203 isCellEditable : function(colIndex, rowIndex){
60204 return colIndex == 1;
60207 getRenderer : function(col){
60209 this.renderCellDelegate : this.renderPropDelegate;
60212 renderProp : function(v){
60213 return this.getPropertyName(v);
60216 renderCell : function(val){
60218 if(val instanceof Date){
60219 rv = this.renderDate(val);
60220 }else if(typeof val == 'boolean'){
60221 rv = this.renderBool(val);
60223 return Roo.util.Format.htmlEncode(rv);
60226 getPropertyName : function(name){
60227 var pn = this.grid.propertyNames;
60228 return pn && pn[name] ? pn[name] : name;
60231 getCellEditor : function(colIndex, rowIndex){
60232 var p = this.store.getProperty(rowIndex);
60233 var n = p.data['name'], val = p.data['value'];
60235 if(typeof(this.grid.customEditors[n]) == 'string'){
60236 return this.editors[this.grid.customEditors[n]];
60238 if(typeof(this.grid.customEditors[n]) != 'undefined'){
60239 return this.grid.customEditors[n];
60241 if(val instanceof Date){
60242 return this.editors['date'];
60243 }else if(typeof val == 'number'){
60244 return this.editors['number'];
60245 }else if(typeof val == 'boolean'){
60246 return this.editors['boolean'];
60248 return this.editors['string'];
60254 * @class Roo.grid.PropertyGrid
60255 * @extends Roo.grid.EditorGrid
60256 * This class represents the interface of a component based property grid control.
60257 * <br><br>Usage:<pre><code>
60258 var grid = new Roo.grid.PropertyGrid("my-container-id", {
60266 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
60267 * The container MUST have some type of size defined for the grid to fill. The container will be
60268 * automatically set to position relative if it isn't already.
60269 * @param {Object} config A config object that sets properties on this grid.
60271 Roo.grid.PropertyGrid = function(container, config){
60272 config = config || {};
60273 var store = new Roo.grid.PropertyStore(this);
60274 this.store = store;
60275 var cm = new Roo.grid.PropertyColumnModel(this, store);
60276 store.store.sort('name', 'ASC');
60277 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
60280 enableColLock:false,
60281 enableColumnMove:false,
60283 trackMouseOver: false,
60286 this.getGridEl().addClass('x-props-grid');
60287 this.lastEditRow = null;
60288 this.on('columnresize', this.onColumnResize, this);
60291 * @event beforepropertychange
60292 * Fires before a property changes (return false to stop?)
60293 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
60294 * @param {String} id Record Id
60295 * @param {String} newval New Value
60296 * @param {String} oldval Old Value
60298 "beforepropertychange": true,
60300 * @event propertychange
60301 * Fires after a property changes
60302 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
60303 * @param {String} id Record Id
60304 * @param {String} newval New Value
60305 * @param {String} oldval Old Value
60307 "propertychange": true
60309 this.customEditors = this.customEditors || {};
60311 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
60314 * @cfg {Object} customEditors map of colnames=> custom editors.
60315 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
60316 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
60317 * false disables editing of the field.
60321 * @cfg {Object} propertyNames map of property Names to their displayed value
60324 render : function(){
60325 Roo.grid.PropertyGrid.superclass.render.call(this);
60326 this.autoSize.defer(100, this);
60329 autoSize : function(){
60330 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
60332 this.view.fitColumns();
60336 onColumnResize : function(){
60337 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
60341 * Sets the data for the Grid
60342 * accepts a Key => Value object of all the elements avaiable.
60343 * @param {Object} data to appear in grid.
60345 setSource : function(source){
60346 this.store.setSource(source);
60350 * Gets all the data from the grid.
60351 * @return {Object} data data stored in grid
60353 getSource : function(){
60354 return this.store.getSource();
60363 * @class Roo.grid.Calendar
60364 * @extends Roo.util.Grid
60365 * This class extends the Grid to provide a calendar widget
60366 * <br><br>Usage:<pre><code>
60367 var grid = new Roo.grid.Calendar("my-container-id", {
60370 selModel: mySelectionModel,
60371 autoSizeColumns: true,
60372 monitorWindowResize: false,
60373 trackMouseOver: true
60374 eventstore : real data store..
60380 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
60381 * The container MUST have some type of size defined for the grid to fill. The container will be
60382 * automatically set to position relative if it isn't already.
60383 * @param {Object} config A config object that sets properties on this grid.
60385 Roo.grid.Calendar = function(container, config){
60386 // initialize the container
60387 this.container = Roo.get(container);
60388 this.container.update("");
60389 this.container.setStyle("overflow", "hidden");
60390 this.container.addClass('x-grid-container');
60392 this.id = this.container.id;
60394 Roo.apply(this, config);
60395 // check and correct shorthanded configs
60399 for (var r = 0;r < 6;r++) {
60402 for (var c =0;c < 7;c++) {
60406 if (this.eventStore) {
60407 this.eventStore= Roo.factory(this.eventStore, Roo.data);
60408 this.eventStore.on('load',this.onLoad, this);
60409 this.eventStore.on('beforeload',this.clearEvents, this);
60413 this.dataSource = new Roo.data.Store({
60414 proxy: new Roo.data.MemoryProxy(rows),
60415 reader: new Roo.data.ArrayReader({}, [
60416 'weekday0', 'weekday1', 'weekday2', 'weekday3', 'weekday4', 'weekday5', 'weekday6' ])
60419 this.dataSource.load();
60420 this.ds = this.dataSource;
60421 this.ds.xmodule = this.xmodule || false;
60424 var cellRender = function(v,x,r)
60426 return String.format(
60427 '<div class="fc-day fc-widget-content"><div>' +
60428 '<div class="fc-event-container"></div>' +
60429 '<div class="fc-day-number">{0}</div>'+
60431 '<div class="fc-day-content"><div style="position:relative"></div></div>' +
60432 '</div></div>', v);
60437 this.colModel = new Roo.grid.ColumnModel( [
60439 xtype: 'ColumnModel',
60441 dataIndex : 'weekday0',
60443 renderer : cellRender
60446 xtype: 'ColumnModel',
60448 dataIndex : 'weekday1',
60450 renderer : cellRender
60453 xtype: 'ColumnModel',
60455 dataIndex : 'weekday2',
60456 header : 'Tuesday',
60457 renderer : cellRender
60460 xtype: 'ColumnModel',
60462 dataIndex : 'weekday3',
60463 header : 'Wednesday',
60464 renderer : cellRender
60467 xtype: 'ColumnModel',
60469 dataIndex : 'weekday4',
60470 header : 'Thursday',
60471 renderer : cellRender
60474 xtype: 'ColumnModel',
60476 dataIndex : 'weekday5',
60478 renderer : cellRender
60481 xtype: 'ColumnModel',
60483 dataIndex : 'weekday6',
60484 header : 'Saturday',
60485 renderer : cellRender
60488 this.cm = this.colModel;
60489 this.cm.xmodule = this.xmodule || false;
60493 //this.selModel = new Roo.grid.CellSelectionModel();
60494 //this.sm = this.selModel;
60495 //this.selModel.init(this);
60499 this.container.setWidth(this.width);
60503 this.container.setHeight(this.height);
60510 * The raw click event for the entire grid.
60511 * @param {Roo.EventObject} e
60516 * The raw dblclick event for the entire grid.
60517 * @param {Roo.EventObject} e
60521 * @event contextmenu
60522 * The raw contextmenu event for the entire grid.
60523 * @param {Roo.EventObject} e
60525 "contextmenu" : true,
60528 * The raw mousedown event for the entire grid.
60529 * @param {Roo.EventObject} e
60531 "mousedown" : true,
60534 * The raw mouseup event for the entire grid.
60535 * @param {Roo.EventObject} e
60540 * The raw mouseover event for the entire grid.
60541 * @param {Roo.EventObject} e
60543 "mouseover" : true,
60546 * The raw mouseout event for the entire grid.
60547 * @param {Roo.EventObject} e
60552 * The raw keypress event for the entire grid.
60553 * @param {Roo.EventObject} e
60558 * The raw keydown event for the entire grid.
60559 * @param {Roo.EventObject} e
60567 * Fires when a cell is clicked
60568 * @param {Grid} this
60569 * @param {Number} rowIndex
60570 * @param {Number} columnIndex
60571 * @param {Roo.EventObject} e
60573 "cellclick" : true,
60575 * @event celldblclick
60576 * Fires when a cell is double clicked
60577 * @param {Grid} this
60578 * @param {Number} rowIndex
60579 * @param {Number} columnIndex
60580 * @param {Roo.EventObject} e
60582 "celldblclick" : true,
60585 * Fires when a row is clicked
60586 * @param {Grid} this
60587 * @param {Number} rowIndex
60588 * @param {Roo.EventObject} e
60592 * @event rowdblclick
60593 * Fires when a row is double clicked
60594 * @param {Grid} this
60595 * @param {Number} rowIndex
60596 * @param {Roo.EventObject} e
60598 "rowdblclick" : true,
60600 * @event headerclick
60601 * Fires when a header is clicked
60602 * @param {Grid} this
60603 * @param {Number} columnIndex
60604 * @param {Roo.EventObject} e
60606 "headerclick" : true,
60608 * @event headerdblclick
60609 * Fires when a header cell is double clicked
60610 * @param {Grid} this
60611 * @param {Number} columnIndex
60612 * @param {Roo.EventObject} e
60614 "headerdblclick" : true,
60616 * @event rowcontextmenu
60617 * Fires when a row is right clicked
60618 * @param {Grid} this
60619 * @param {Number} rowIndex
60620 * @param {Roo.EventObject} e
60622 "rowcontextmenu" : true,
60624 * @event cellcontextmenu
60625 * Fires when a cell is right clicked
60626 * @param {Grid} this
60627 * @param {Number} rowIndex
60628 * @param {Number} cellIndex
60629 * @param {Roo.EventObject} e
60631 "cellcontextmenu" : true,
60633 * @event headercontextmenu
60634 * Fires when a header is right clicked
60635 * @param {Grid} this
60636 * @param {Number} columnIndex
60637 * @param {Roo.EventObject} e
60639 "headercontextmenu" : true,
60641 * @event bodyscroll
60642 * Fires when the body element is scrolled
60643 * @param {Number} scrollLeft
60644 * @param {Number} scrollTop
60646 "bodyscroll" : true,
60648 * @event columnresize
60649 * Fires when the user resizes a column
60650 * @param {Number} columnIndex
60651 * @param {Number} newSize
60653 "columnresize" : true,
60655 * @event columnmove
60656 * Fires when the user moves a column
60657 * @param {Number} oldIndex
60658 * @param {Number} newIndex
60660 "columnmove" : true,
60663 * Fires when row(s) start being dragged
60664 * @param {Grid} this
60665 * @param {Roo.GridDD} dd The drag drop object
60666 * @param {event} e The raw browser event
60668 "startdrag" : true,
60671 * Fires when a drag operation is complete
60672 * @param {Grid} this
60673 * @param {Roo.GridDD} dd The drag drop object
60674 * @param {event} e The raw browser event
60679 * Fires when dragged row(s) are dropped on a valid DD target
60680 * @param {Grid} this
60681 * @param {Roo.GridDD} dd The drag drop object
60682 * @param {String} targetId The target drag drop object
60683 * @param {event} e The raw browser event
60688 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
60689 * @param {Grid} this
60690 * @param {Roo.GridDD} dd The drag drop object
60691 * @param {String} targetId The target drag drop object
60692 * @param {event} e The raw browser event
60697 * Fires when the dragged row(s) first cross another DD target while being dragged
60698 * @param {Grid} this
60699 * @param {Roo.GridDD} dd The drag drop object
60700 * @param {String} targetId The target drag drop object
60701 * @param {event} e The raw browser event
60703 "dragenter" : true,
60706 * Fires when the dragged row(s) leave another DD target while being dragged
60707 * @param {Grid} this
60708 * @param {Roo.GridDD} dd The drag drop object
60709 * @param {String} targetId The target drag drop object
60710 * @param {event} e The raw browser event
60715 * Fires when a row is rendered, so you can change add a style to it.
60716 * @param {GridView} gridview The grid view
60717 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
60723 * Fires when the grid is rendered
60724 * @param {Grid} grid
60729 * Fires when a date is selected
60730 * @param {DatePicker} this
60731 * @param {Date} date The selected date
60735 * @event monthchange
60736 * Fires when the displayed month changes
60737 * @param {DatePicker} this
60738 * @param {Date} date The selected month
60740 'monthchange': true,
60742 * @event evententer
60743 * Fires when mouse over an event
60744 * @param {Calendar} this
60745 * @param {event} Event
60747 'evententer': true,
60749 * @event eventleave
60750 * Fires when the mouse leaves an
60751 * @param {Calendar} this
60754 'eventleave': true,
60756 * @event eventclick
60757 * Fires when the mouse click an
60758 * @param {Calendar} this
60761 'eventclick': true,
60763 * @event eventrender
60764 * Fires before each cell is rendered, so you can modify the contents, like cls / title / qtip
60765 * @param {Calendar} this
60766 * @param {data} data to be modified
60768 'eventrender': true
60772 Roo.grid.Grid.superclass.constructor.call(this);
60773 this.on('render', function() {
60774 this.view.el.addClass('x-grid-cal');
60776 (function() { this.setDate(new Date()); }).defer(100,this); //default today..
60780 if (!Roo.grid.Calendar.style) {
60781 Roo.grid.Calendar.style = Roo.util.CSS.createStyleSheet({
60784 '.x-grid-cal .x-grid-col' : {
60785 height: 'auto !important',
60786 'vertical-align': 'top'
60788 '.x-grid-cal .fc-event-hori' : {
60799 Roo.extend(Roo.grid.Calendar, Roo.grid.Grid, {
60801 * @cfg {Store} eventStore The store that loads events.
60806 activeDate : false,
60809 monitorWindowResize : false,
60812 resizeColumns : function() {
60813 var col = (this.view.el.getWidth() / 7) - 3;
60814 // loop through cols, and setWidth
60815 for(var i =0 ; i < 7 ; i++){
60816 this.cm.setColumnWidth(i, col);
60819 setDate :function(date) {
60821 Roo.log('setDate?');
60823 this.resizeColumns();
60824 var vd = this.activeDate;
60825 this.activeDate = date;
60826 // if(vd && this.el){
60827 // var t = date.getTime();
60828 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
60829 // Roo.log('using add remove');
60831 // this.fireEvent('monthchange', this, date);
60833 // this.cells.removeClass("fc-state-highlight");
60834 // this.cells.each(function(c){
60835 // if(c.dateValue == t){
60836 // c.addClass("fc-state-highlight");
60837 // setTimeout(function(){
60838 // try{c.dom.firstChild.focus();}catch(e){}
60848 var days = date.getDaysInMonth();
60850 var firstOfMonth = date.getFirstDateOfMonth();
60851 var startingPos = firstOfMonth.getDay()-this.startDay;
60853 if(startingPos < this.startDay){
60857 var pm = date.add(Date.MONTH, -1);
60858 var prevStart = pm.getDaysInMonth()-startingPos;
60862 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
60864 this.textNodes = this.view.el.query('.x-grid-row .x-grid-col .x-grid-cell-text');
60865 //this.cells.addClassOnOver('fc-state-hover');
60867 var cells = this.cells.elements;
60868 var textEls = this.textNodes;
60870 //Roo.each(cells, function(cell){
60871 // cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
60874 days += startingPos;
60876 // convert everything to numbers so it's fast
60877 var day = 86400000;
60878 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
60881 //Roo.log(prevStart);
60883 var today = new Date().clearTime().getTime();
60884 var sel = date.clearTime().getTime();
60885 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
60886 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
60887 var ddMatch = this.disabledDatesRE;
60888 var ddText = this.disabledDatesText;
60889 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
60890 var ddaysText = this.disabledDaysText;
60891 var format = this.format;
60893 var setCellClass = function(cal, cell){
60895 //Roo.log('set Cell Class');
60897 var t = d.getTime();
60902 cell.dateValue = t;
60904 cell.className += " fc-today";
60905 cell.className += " fc-state-highlight";
60906 cell.title = cal.todayText;
60909 // disable highlight in other month..
60910 cell.className += " fc-state-highlight";
60915 //cell.className = " fc-state-disabled";
60916 cell.title = cal.minText;
60920 //cell.className = " fc-state-disabled";
60921 cell.title = cal.maxText;
60925 if(ddays.indexOf(d.getDay()) != -1){
60926 // cell.title = ddaysText;
60927 // cell.className = " fc-state-disabled";
60930 if(ddMatch && format){
60931 var fvalue = d.dateFormat(format);
60932 if(ddMatch.test(fvalue)){
60933 cell.title = ddText.replace("%0", fvalue);
60934 cell.className = " fc-state-disabled";
60938 if (!cell.initialClassName) {
60939 cell.initialClassName = cell.dom.className;
60942 cell.dom.className = cell.initialClassName + ' ' + cell.className;
60947 for(; i < startingPos; i++) {
60948 cells[i].dayName = (++prevStart);
60949 Roo.log(textEls[i]);
60950 d.setDate(d.getDate()+1);
60952 //cells[i].className = "fc-past fc-other-month";
60953 setCellClass(this, cells[i]);
60958 for(; i < days; i++){
60959 intDay = i - startingPos + 1;
60960 cells[i].dayName = (intDay);
60961 d.setDate(d.getDate()+1);
60963 cells[i].className = ''; // "x-date-active";
60964 setCellClass(this, cells[i]);
60968 for(; i < 42; i++) {
60969 //textEls[i].innerHTML = (++extraDays);
60971 d.setDate(d.getDate()+1);
60972 cells[i].dayName = (++extraDays);
60973 cells[i].className = "fc-future fc-other-month";
60974 setCellClass(this, cells[i]);
60977 //this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
60979 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
60981 // this will cause all the cells to mis
60984 for (var r = 0;r < 6;r++) {
60985 for (var c =0;c < 7;c++) {
60986 this.ds.getAt(r).set('weekday' + c ,cells[i++].dayName );
60990 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
60991 for(i=0;i<cells.length;i++) {
60993 this.cells.elements[i].dayName = cells[i].dayName ;
60994 this.cells.elements[i].className = cells[i].className;
60995 this.cells.elements[i].initialClassName = cells[i].initialClassName ;
60996 this.cells.elements[i].title = cells[i].title ;
60997 this.cells.elements[i].dateValue = cells[i].dateValue ;
61003 //this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
61004 //this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
61006 ////if(totalRows != 6){
61007 //this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
61008 // this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
61011 this.fireEvent('monthchange', this, date);
61016 * Returns the grid's SelectionModel.
61017 * @return {SelectionModel}
61019 getSelectionModel : function(){
61020 if(!this.selModel){
61021 this.selModel = new Roo.grid.CellSelectionModel();
61023 return this.selModel;
61027 this.eventStore.load()
61033 findCell : function(dt) {
61034 dt = dt.clearTime().getTime();
61036 this.cells.each(function(c){
61037 //Roo.log("check " +c.dateValue + '?=' + dt);
61038 if(c.dateValue == dt){
61048 findCells : function(rec) {
61049 var s = rec.data.start_dt.clone().clearTime().getTime();
61051 var e= rec.data.end_dt.clone().clearTime().getTime();
61054 this.cells.each(function(c){
61055 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
61057 if(c.dateValue > e){
61060 if(c.dateValue < s){
61069 findBestRow: function(cells)
61073 for (var i =0 ; i < cells.length;i++) {
61074 ret = Math.max(cells[i].rows || 0,ret);
61081 addItem : function(rec)
61083 // look for vertical location slot in
61084 var cells = this.findCells(rec);
61086 rec.row = this.findBestRow(cells);
61088 // work out the location.
61092 for(var i =0; i < cells.length; i++) {
61100 if (crow.start.getY() == cells[i].getY()) {
61102 crow.end = cells[i];
61118 for (var i = 0; i < cells.length;i++) {
61119 cells[i].rows = Math.max(cells[i].rows || 0 , rec.row + 1 );
61126 clearEvents: function() {
61128 if (!this.eventStore.getCount()) {
61131 // reset number of rows in cells.
61132 Roo.each(this.cells.elements, function(c){
61136 this.eventStore.each(function(e) {
61137 this.clearEvent(e);
61142 clearEvent : function(ev)
61145 Roo.each(ev.els, function(el) {
61146 el.un('mouseenter' ,this.onEventEnter, this);
61147 el.un('mouseleave' ,this.onEventLeave, this);
61155 renderEvent : function(ev,ctr) {
61157 ctr = this.view.el.select('.fc-event-container',true).first();
61161 this.clearEvent(ev);
61167 var cells = ev.cells;
61168 var rows = ev.rows;
61169 this.fireEvent('eventrender', this, ev);
61171 for(var i =0; i < rows.length; i++) {
61175 cls += ' fc-event-start';
61177 if ((i+1) == rows.length) {
61178 cls += ' fc-event-end';
61181 //Roo.log(ev.data);
61182 // how many rows should it span..
61183 var cg = this.eventTmpl.append(ctr,Roo.apply({
61186 }, ev.data) , true);
61189 cg.on('mouseenter' ,this.onEventEnter, this, ev);
61190 cg.on('mouseleave' ,this.onEventLeave, this, ev);
61191 cg.on('click', this.onEventClick, this, ev);
61195 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
61196 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
61199 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);
61200 cg.setWidth(ebox.right - sbox.x -2);
61204 renderEvents: function()
61206 // first make sure there is enough space..
61208 if (!this.eventTmpl) {
61209 this.eventTmpl = new Roo.Template(
61210 '<div class="roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable {fccls} {cls}" style="position: absolute" unselectable="on">' +
61211 '<div class="fc-event-inner">' +
61212 '<span class="fc-event-time">{time}</span>' +
61213 '<span class="fc-event-title" qtip="{qtip}">{title}</span>' +
61215 '<div class="ui-resizable-heandle ui-resizable-e"> </div>' +
61223 this.cells.each(function(c) {
61224 //Roo.log(c.select('.fc-day-content div',true).first());
61225 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, (c.rows || 1) * 20));
61228 var ctr = this.view.el.select('.fc-event-container',true).first();
61231 this.eventStore.each(function(ev){
61233 this.renderEvent(ev);
61237 this.view.layout();
61241 onEventEnter: function (e, el,event,d) {
61242 this.fireEvent('evententer', this, el, event);
61245 onEventLeave: function (e, el,event,d) {
61246 this.fireEvent('eventleave', this, el, event);
61249 onEventClick: function (e, el,event,d) {
61250 this.fireEvent('eventclick', this, el, event);
61253 onMonthChange: function () {
61257 onLoad: function () {
61259 //Roo.log('calendar onload');
61261 if(this.eventStore.getCount() > 0){
61265 this.eventStore.each(function(d){
61270 if (typeof(add.end_dt) == 'undefined') {
61271 Roo.log("Missing End time in calendar data: ");
61275 if (typeof(add.start_dt) == 'undefined') {
61276 Roo.log("Missing Start time in calendar data: ");
61280 add.start_dt = typeof(add.start_dt) == 'string' ? Date.parseDate(add.start_dt,'Y-m-d H:i:s') : add.start_dt,
61281 add.end_dt = typeof(add.end_dt) == 'string' ? Date.parseDate(add.end_dt,'Y-m-d H:i:s') : add.end_dt,
61282 add.id = add.id || d.id;
61283 add.title = add.title || '??';
61291 this.renderEvents();
61301 render : function ()
61305 if (!this.view.el.hasClass('course-timesheet')) {
61306 this.view.el.addClass('course-timesheet');
61308 if (this.tsStyle) {
61313 Roo.log(_this.grid.view.el.getWidth());
61316 this.tsStyle = Roo.util.CSS.createStyleSheet({
61317 '.course-timesheet .x-grid-row' : {
61320 '.x-grid-row td' : {
61321 'vertical-align' : 0
61323 '.course-edit-link' : {
61325 'text-overflow' : 'ellipsis',
61326 'overflow' : 'hidden',
61327 'white-space' : 'nowrap',
61328 'cursor' : 'pointer'
61333 '.de-act-sup-link' : {
61334 'color' : 'purple',
61335 'text-decoration' : 'line-through'
61339 'text-decoration' : 'line-through'
61341 '.course-timesheet .course-highlight' : {
61342 'border-top-style': 'dashed !important',
61343 'border-bottom-bottom': 'dashed !important'
61345 '.course-timesheet .course-item' : {
61346 'font-family' : 'tahoma, arial, helvetica',
61347 'font-size' : '11px',
61348 'overflow' : 'hidden',
61349 'padding-left' : '10px',
61350 'padding-right' : '10px',
61351 'padding-top' : '10px'
61359 monitorWindowResize : false,
61360 cellrenderer : function(v,x,r)
61365 xtype: 'CellSelectionModel',
61372 beforeload : function (_self, options)
61374 options.params = options.params || {};
61375 options.params._month = _this.monthField.getValue();
61376 options.params.limit = 9999;
61377 options.params['sort'] = 'when_dt';
61378 options.params['dir'] = 'ASC';
61379 this.proxy.loadResponse = this.loadResponse;
61381 //this.addColumns();
61383 load : function (_self, records, options)
61385 _this.grid.view.el.select('.course-edit-link', true).on('click', function() {
61386 // if you click on the translation.. you can edit it...
61387 var el = Roo.get(this);
61388 var id = el.dom.getAttribute('data-id');
61389 var d = el.dom.getAttribute('data-date');
61390 var t = el.dom.getAttribute('data-time');
61391 //var id = this.child('span').dom.textContent;
61394 Pman.Dialog.CourseCalendar.show({
61398 productitem_active : id ? 1 : 0
61400 _this.grid.ds.load({});
61405 _this.panel.fireEvent('resize', [ '', '' ]);
61408 loadResponse : function(o, success, response){
61409 // this is overridden on before load..
61411 Roo.log("our code?");
61412 //Roo.log(success);
61413 //Roo.log(response)
61414 delete this.activeRequest;
61416 this.fireEvent("loadexception", this, o, response);
61417 o.request.callback.call(o.request.scope, null, o.request.arg, false);
61422 result = o.reader.read(response);
61424 Roo.log("load exception?");
61425 this.fireEvent("loadexception", this, o, response, e);
61426 o.request.callback.call(o.request.scope, null, o.request.arg, false);
61429 Roo.log("ready...");
61430 // loop through result.records;
61431 // and set this.tdate[date] = [] << array of records..
61433 Roo.each(result.records, function(r){
61435 if(typeof(_this.tdata[r.data.when_dt.format('j')]) == 'undefined'){
61436 _this.tdata[r.data.when_dt.format('j')] = [];
61438 _this.tdata[r.data.when_dt.format('j')].push(r.data);
61441 //Roo.log(_this.tdata);
61443 result.records = [];
61444 result.totalRecords = 6;
61446 // let's generate some duumy records for the rows.
61447 //var st = _this.dateField.getValue();
61449 // work out monday..
61450 //st = st.add(Date.DAY, -1 * st.format('w'));
61452 var date = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
61454 var firstOfMonth = date.getFirstDayOfMonth();
61455 var days = date.getDaysInMonth();
61457 var firstAdded = false;
61458 for (var i = 0; i < result.totalRecords ; i++) {
61459 //var d= st.add(Date.DAY, i);
61462 for(var w = 0 ; w < 7 ; w++){
61463 if(!firstAdded && firstOfMonth != w){
61470 var dd = (d > 0 && d < 10) ? "0"+d : d;
61471 row['weekday'+w] = String.format(
61472 '<span style="font-size: 16px;"><b>{0}</b></span>'+
61473 '<span class="course-edit-link" style="color:blue;" data-id="0" data-date="{1}"> Add New</span>',
61475 date.format('Y-m-')+dd
61478 if(typeof(_this.tdata[d]) != 'undefined'){
61479 Roo.each(_this.tdata[d], function(r){
61483 var desc = (r.productitem_id_descrip) ? r.productitem_id_descrip : '';
61484 if(r.parent_id*1>0){
61485 is_sub = (r.productitem_id_visible*1 < 1) ? 'de-act-sup-link' :'sub-link';
61488 if(r.productitem_id_visible*1 < 1 && r.parent_id*1 < 1){
61489 deactive = 'de-act-link';
61492 row['weekday'+w] += String.format(
61493 '<br /><span class="course-edit-link {3} {4}" qtip="{5}" data-id="{0}">{2} - {1}</span>',
61495 r.product_id_name, //1
61496 r.when_dt.format('h:ia'), //2
61506 // only do this if something added..
61508 result.records.push(_this.grid.dataSource.reader.newRow(row));
61512 // push it twice. (second one with an hour..
61516 this.fireEvent("load", this, o, o.request.arg);
61517 o.request.callback.call(o.request.scope, result, o.request.arg, true);
61519 sortInfo : {field: 'when_dt', direction : 'ASC' },
61521 xtype: 'HttpProxy',
61524 url : baseURL + '/Roo/Shop_course.php'
61527 xtype: 'JsonReader',
61544 'name': 'parent_id',
61548 'name': 'product_id',
61552 'name': 'productitem_id',
61570 click : function (_self, e)
61572 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
61573 sd.setMonth(sd.getMonth()-1);
61574 _this.monthField.setValue(sd.format('Y-m-d'));
61575 _this.grid.ds.load({});
61581 xtype: 'Separator',
61585 xtype: 'MonthField',
61588 render : function (_self)
61590 _this.monthField = _self;
61591 // _this.monthField.set today
61593 select : function (combo, date)
61595 _this.grid.ds.load({});
61598 value : (function() { return new Date(); })()
61601 xtype: 'Separator',
61607 text : "Blue: in-active, green: in-active sup-event, red: de-active, purple: de-active sup-event"
61617 click : function (_self, e)
61619 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
61620 sd.setMonth(sd.getMonth()+1);
61621 _this.monthField.setValue(sd.format('Y-m-d'));
61622 _this.grid.ds.load({});
61635 * Ext JS Library 1.1.1
61636 * Copyright(c) 2006-2007, Ext JS, LLC.
61638 * Originally Released Under LGPL - original licence link has changed is not relivant.
61641 * <script type="text/javascript">
61645 * @class Roo.LoadMask
61646 * A simple utility class for generically masking elements while loading data. If the element being masked has
61647 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
61648 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
61649 * element's UpdateManager load indicator and will be destroyed after the initial load.
61651 * Create a new LoadMask
61652 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
61653 * @param {Object} config The config object
61655 Roo.LoadMask = function(el, config){
61656 this.el = Roo.get(el);
61657 Roo.apply(this, config);
61659 this.store.on('beforeload', this.onBeforeLoad, this);
61660 this.store.on('load', this.onLoad, this);
61661 this.store.on('loadexception', this.onLoadException, this);
61662 this.removeMask = false;
61664 var um = this.el.getUpdateManager();
61665 um.showLoadIndicator = false; // disable the default indicator
61666 um.on('beforeupdate', this.onBeforeLoad, this);
61667 um.on('update', this.onLoad, this);
61668 um.on('failure', this.onLoad, this);
61669 this.removeMask = true;
61673 Roo.LoadMask.prototype = {
61675 * @cfg {Boolean} removeMask
61676 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
61677 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
61679 removeMask : false,
61681 * @cfg {String} msg
61682 * The text to display in a centered loading message box (defaults to 'Loading...')
61684 msg : 'Loading...',
61686 * @cfg {String} msgCls
61687 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
61689 msgCls : 'x-mask-loading',
61692 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
61698 * Disables the mask to prevent it from being displayed
61700 disable : function(){
61701 this.disabled = true;
61705 * Enables the mask so that it can be displayed
61707 enable : function(){
61708 this.disabled = false;
61711 onLoadException : function()
61713 Roo.log(arguments);
61715 if (typeof(arguments[3]) != 'undefined') {
61716 Roo.MessageBox.alert("Error loading",arguments[3]);
61720 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
61721 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
61728 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
61731 onLoad : function()
61733 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
61737 onBeforeLoad : function(){
61738 if(!this.disabled){
61739 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
61744 destroy : function(){
61746 this.store.un('beforeload', this.onBeforeLoad, this);
61747 this.store.un('load', this.onLoad, this);
61748 this.store.un('loadexception', this.onLoadException, this);
61750 var um = this.el.getUpdateManager();
61751 um.un('beforeupdate', this.onBeforeLoad, this);
61752 um.un('update', this.onLoad, this);
61753 um.un('failure', this.onLoad, this);
61758 * Ext JS Library 1.1.1
61759 * Copyright(c) 2006-2007, Ext JS, LLC.
61761 * Originally Released Under LGPL - original licence link has changed is not relivant.
61764 * <script type="text/javascript">
61769 * @class Roo.XTemplate
61770 * @extends Roo.Template
61771 * Provides a template that can have nested templates for loops or conditionals. The syntax is:
61773 var t = new Roo.XTemplate(
61774 '<select name="{name}">',
61775 '<tpl for="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
61779 // then append, applying the master template values
61782 * Supported features:
61787 {a_variable} - output encoded.
61788 {a_variable.format:("Y-m-d")} - call a method on the variable
61789 {a_variable:raw} - unencoded output
61790 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
61791 {a_variable:this.method_on_template(...)} - call a method on the template object.
61796 <tpl for="a_variable or condition.."></tpl>
61797 <tpl if="a_variable or condition"></tpl>
61798 <tpl exec="some javascript"></tpl>
61799 <tpl name="named_template"></tpl> (experimental)
61801 <tpl for="."></tpl> - just iterate the property..
61802 <tpl for=".."></tpl> - iterates with the parent (probably the template)
61806 Roo.XTemplate = function()
61808 Roo.XTemplate.superclass.constructor.apply(this, arguments);
61815 Roo.extend(Roo.XTemplate, Roo.Template, {
61818 * The various sub templates
61823 * basic tag replacing syntax
61826 * // you can fake an object call by doing this
61830 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
61833 * compile the template
61835 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
61838 compile: function()
61842 s = ['<tpl>', s, '</tpl>'].join('');
61844 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
61845 nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
61846 ifRe = /^<tpl\b[^>]*?if="(.*?)"/,
61847 execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
61848 namedRe = /^<tpl\b[^>]*?name="(\w+)"/, // named templates..
61853 while(true == !!(m = s.match(re))){
61854 var forMatch = m[0].match(nameRe),
61855 ifMatch = m[0].match(ifRe),
61856 execMatch = m[0].match(execRe),
61857 namedMatch = m[0].match(namedRe),
61862 name = forMatch && forMatch[1] ? forMatch[1] : '';
61865 // if - puts fn into test..
61866 exp = ifMatch && ifMatch[1] ? ifMatch[1] : null;
61868 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
61873 // exec - calls a function... returns empty if true is returned.
61874 exp = execMatch && execMatch[1] ? execMatch[1] : null;
61876 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
61884 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
61885 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
61886 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
61889 var uid = namedMatch ? namedMatch[1] : id;
61893 id: namedMatch ? namedMatch[1] : id,
61900 s = s.replace(m[0], '');
61902 s = s.replace(m[0], '{xtpl'+ id + '}');
61907 for(var i = tpls.length-1; i >= 0; --i){
61908 this.compileTpl(tpls[i]);
61909 this.tpls[tpls[i].id] = tpls[i];
61911 this.master = tpls[tpls.length-1];
61915 * same as applyTemplate, except it's done to one of the subTemplates
61916 * when using named templates, you can do:
61918 * var str = pl.applySubTemplate('your-name', values);
61921 * @param {Number} id of the template
61922 * @param {Object} values to apply to template
61923 * @param {Object} parent (normaly the instance of this object)
61925 applySubTemplate : function(id, values, parent)
61929 var t = this.tpls[id];
61933 if(t.test && !t.test.call(this, values, parent)){
61937 Roo.log("Xtemplate.applySubTemplate 'test': Exception thrown");
61938 Roo.log(e.toString());
61944 if(t.exec && t.exec.call(this, values, parent)){
61948 Roo.log("Xtemplate.applySubTemplate 'exec': Exception thrown");
61949 Roo.log(e.toString());
61954 var vs = t.target ? t.target.call(this, values, parent) : values;
61955 parent = t.target ? values : parent;
61956 if(t.target && vs instanceof Array){
61958 for(var i = 0, len = vs.length; i < len; i++){
61959 buf[buf.length] = t.compiled.call(this, vs[i], parent);
61961 return buf.join('');
61963 return t.compiled.call(this, vs, parent);
61965 Roo.log("Xtemplate.applySubTemplate : Exception thrown");
61966 Roo.log(e.toString());
61967 Roo.log(t.compiled);
61972 compileTpl : function(tpl)
61974 var fm = Roo.util.Format;
61975 var useF = this.disableFormats !== true;
61976 var sep = Roo.isGecko ? "+" : ",";
61977 var undef = function(str) {
61978 Roo.log("Property not found :" + str);
61982 var fn = function(m, name, format, args)
61984 //Roo.log(arguments);
61985 args = args ? args.replace(/\\'/g,"'") : args;
61986 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
61987 if (typeof(format) == 'undefined') {
61988 format= 'htmlEncode';
61990 if (format == 'raw' ) {
61994 if(name.substr(0, 4) == 'xtpl'){
61995 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
61998 // build an array of options to determine if value is undefined..
62000 // basically get 'xxxx.yyyy' then do
62001 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
62002 // (function () { Roo.log("Property not found"); return ''; })() :
62007 Roo.each(name.split('.'), function(st) {
62008 lookfor += (lookfor.length ? '.': '') + st;
62009 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
62012 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
62015 if(format && useF){
62017 args = args ? ',' + args : "";
62019 if(format.substr(0, 5) != "this."){
62020 format = "fm." + format + '(';
62022 format = 'this.call("'+ format.substr(5) + '", ';
62026 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
62030 // called with xxyx.yuu:(test,test)
62032 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
62034 // raw.. - :raw modifier..
62035 return "'"+ sep + udef_st + name + ")"+sep+"'";
62039 // branched to use + in gecko and [].join() in others
62041 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
62042 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
62045 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
62046 body.push(tpl.body.replace(/(\r\n|\n)/g,
62047 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
62048 body.push("'].join('');};};");
62049 body = body.join('');
62052 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
62054 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
62060 applyTemplate : function(values){
62061 return this.master.compiled.call(this, values, {});
62062 //var s = this.subs;
62065 apply : function(){
62066 return this.applyTemplate.apply(this, arguments);
62071 Roo.XTemplate.from = function(el){
62072 el = Roo.getDom(el);
62073 return new Roo.XTemplate(el.value || el.innerHTML);