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);
678 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
679 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout",
682 "Roo.bootstrap.dash");
685 * Ext JS Library 1.1.1
686 * Copyright(c) 2006-2007, Ext JS, LLC.
688 * Originally Released Under LGPL - original licence link has changed is not relivant.
691 * <script type="text/javascript">
695 // wrappedn so fnCleanup is not in global scope...
697 function fnCleanUp() {
698 var p = Function.prototype;
699 delete p.createSequence;
701 delete p.createDelegate;
702 delete p.createCallback;
703 delete p.createInterceptor;
705 window.detachEvent("onunload", fnCleanUp);
707 window.attachEvent("onunload", fnCleanUp);
714 * These functions are available on every Function object (any JavaScript function).
716 Roo.apply(Function.prototype, {
718 * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
719 * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
720 * Will create a function that is bound to those 2 args.
721 * @return {Function} The new function
723 createCallback : function(/*args...*/){
724 // make args available, in function below
725 var args = arguments;
728 return method.apply(window, args);
733 * Creates a delegate (callback) that sets the scope to obj.
734 * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
735 * Will create a function that is automatically scoped to this.
736 * @param {Object} obj (optional) The object for which the scope is set
737 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
738 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
739 * if a number the args are inserted at the specified position
740 * @return {Function} The new function
742 createDelegate : function(obj, args, appendArgs){
745 var callArgs = args || arguments;
746 if(appendArgs === true){
747 callArgs = Array.prototype.slice.call(arguments, 0);
748 callArgs = callArgs.concat(args);
749 }else if(typeof appendArgs == "number"){
750 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
751 var applyArgs = [appendArgs, 0].concat(args); // create method call params
752 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
754 return method.apply(obj || window, callArgs);
759 * Calls this function after the number of millseconds specified.
760 * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
761 * @param {Object} obj (optional) The object for which the scope is set
762 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
763 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
764 * if a number the args are inserted at the specified position
765 * @return {Number} The timeout id that can be used with clearTimeout
767 defer : function(millis, obj, args, appendArgs){
768 var fn = this.createDelegate(obj, args, appendArgs);
770 return setTimeout(fn, millis);
776 * Create a combined function call sequence of the original function + the passed function.
777 * The resulting function returns the results of the original function.
778 * The passed fcn is called with the parameters of the original function
779 * @param {Function} fcn The function to sequence
780 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
781 * @return {Function} The new function
783 createSequence : function(fcn, scope){
784 if(typeof fcn != "function"){
789 var retval = method.apply(this || window, arguments);
790 fcn.apply(scope || this || window, arguments);
796 * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
797 * The resulting function returns the results of the original function.
798 * The passed fcn is called with the parameters of the original function.
800 * @param {Function} fcn The function to call before the original
801 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
802 * @return {Function} The new function
804 createInterceptor : function(fcn, scope){
805 if(typeof fcn != "function"){
812 if(fcn.apply(scope || this || window, arguments) === false){
815 return method.apply(this || window, arguments);
821 * Ext JS Library 1.1.1
822 * Copyright(c) 2006-2007, Ext JS, LLC.
824 * Originally Released Under LGPL - original licence link has changed is not relivant.
827 * <script type="text/javascript">
830 Roo.applyIf(String, {
835 * Escapes the passed string for ' and \
836 * @param {String} string The string to escape
837 * @return {String} The escaped string
840 escape : function(string) {
841 return string.replace(/('|\\)/g, "\\$1");
845 * Pads the left side of a string with a specified character. This is especially useful
846 * for normalizing number and date strings. Example usage:
848 var s = String.leftPad('123', 5, '0');
849 // s now contains the string: '00123'
851 * @param {String} string The original string
852 * @param {Number} size The total length of the output string
853 * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
854 * @return {String} The padded string
857 leftPad : function (val, size, ch) {
858 var result = new String(val);
859 if(ch === null || ch === undefined || ch === '') {
862 while (result.length < size) {
863 result = ch + result;
869 * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens. Each
870 * token must be unique, and must increment in the format {0}, {1}, etc. Example usage:
872 var cls = 'my-class', text = 'Some text';
873 var s = String.format('<div class="{0}">{1}</div>', cls, text);
874 // s now contains the string: '<div class="my-class">Some text</div>'
876 * @param {String} string The tokenized string to be formatted
877 * @param {String} value1 The value to replace token {0}
878 * @param {String} value2 Etc...
879 * @return {String} The formatted string
882 format : function(format){
883 var args = Array.prototype.slice.call(arguments, 1);
884 return format.replace(/\{(\d+)\}/g, function(m, i){
885 return Roo.util.Format.htmlEncode(args[i]);
893 * Utility function that allows you to easily switch a string between two alternating values. The passed value
894 * is compared to the current string, and if they are equal, the other value that was passed in is returned. If
895 * they are already different, the first value passed in is returned. Note that this method returns the new value
896 * but does not change the current string.
898 // alternate sort directions
899 sort = sort.toggle('ASC', 'DESC');
901 // instead of conditional logic:
902 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
904 * @param {String} value The value to compare to the current string
905 * @param {String} other The new value to use if the string already equals the first value passed in
906 * @return {String} The new value
909 String.prototype.toggle = function(value, other){
910 return this == value ? other : value;
915 * Remove invalid unicode characters from a string
917 * @return {String} The clean string
919 String.prototype.unicodeClean = function () {
920 return this.replace(/[\s\S]/g,
921 function(character) {
922 if (character.charCodeAt()< 256) {
926 encodeURIComponent(character);
937 * Ext JS Library 1.1.1
938 * Copyright(c) 2006-2007, Ext JS, LLC.
940 * Originally Released Under LGPL - original licence link has changed is not relivant.
943 * <script type="text/javascript">
949 Roo.applyIf(Number.prototype, {
951 * Checks whether or not the current number is within a desired range. If the number is already within the
952 * range it is returned, otherwise the min or max value is returned depending on which side of the range is
953 * exceeded. Note that this method returns the constrained value but does not change the current number.
954 * @param {Number} min The minimum number in the range
955 * @param {Number} max The maximum number in the range
956 * @return {Number} The constrained value if outside the range, otherwise the current value
958 constrain : function(min, max){
959 return Math.min(Math.max(this, min), max);
963 * Ext JS Library 1.1.1
964 * Copyright(c) 2006-2007, Ext JS, LLC.
966 * Originally Released Under LGPL - original licence link has changed is not relivant.
969 * <script type="text/javascript">
974 Roo.applyIf(Array.prototype, {
977 * Checks whether or not the specified object exists in the array.
978 * @param {Object} o The object to check for
979 * @return {Number} The index of o in the array (or -1 if it is not found)
981 indexOf : function(o){
982 for (var i = 0, len = this.length; i < len; i++){
983 if(this[i] == o) { return i; }
989 * Removes the specified object from the array. If the object is not found nothing happens.
990 * @param {Object} o The object to remove
992 remove : function(o){
993 var index = this.indexOf(o);
995 this.splice(index, 1);
999 * Map (JS 1.6 compatibility)
1000 * @param {Function} function to call
1002 map : function(fun )
1004 var len = this.length >>> 0;
1005 if (typeof fun != "function") {
1006 throw new TypeError();
1008 var res = new Array(len);
1009 var thisp = arguments[1];
1010 for (var i = 0; i < len; i++)
1013 res[i] = fun.call(thisp, this[i], i, this);
1021 * @param {Array} o The array to compare to
1022 * @returns {Boolean} true if the same
1024 equals : function(b)
1026 // https://stackoverflow.com/questions/3115982/how-to-check-if-two-arrays-are-equal-with-javascript
1033 if (this.length !== b.length) {
1037 // sort?? a.sort().equals(b.sort());
1039 for (var i = 0; i < this.length; ++i) {
1040 if (this[i] !== b[i]) {
1052 * Ext JS Library 1.1.1
1053 * Copyright(c) 2006-2007, Ext JS, LLC.
1055 * Originally Released Under LGPL - original licence link has changed is not relivant.
1058 * <script type="text/javascript">
1064 * The date parsing and format syntax is a subset of
1065 * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
1066 * supported will provide results equivalent to their PHP versions.
1068 * Following is the list of all currently supported formats:
1071 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
1073 Format Output Description
1074 ------ ---------- --------------------------------------------------------------
1075 d 10 Day of the month, 2 digits with leading zeros
1076 D Wed A textual representation of a day, three letters
1077 j 10 Day of the month without leading zeros
1078 l Wednesday A full textual representation of the day of the week
1079 S th English ordinal day of month suffix, 2 chars (use with j)
1080 w 3 Numeric representation of the day of the week
1081 z 9 The julian date, or day of the year (0-365)
1082 W 01 ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
1083 F January A full textual representation of the month
1084 m 01 Numeric representation of a month, with leading zeros
1085 M Jan Month name abbreviation, three letters
1086 n 1 Numeric representation of a month, without leading zeros
1087 t 31 Number of days in the given month
1088 L 0 Whether it's a leap year (1 if it is a leap year, else 0)
1089 Y 2007 A full numeric representation of a year, 4 digits
1090 y 07 A two digit representation of a year
1091 a pm Lowercase Ante meridiem and Post meridiem
1092 A PM Uppercase Ante meridiem and Post meridiem
1093 g 3 12-hour format of an hour without leading zeros
1094 G 15 24-hour format of an hour without leading zeros
1095 h 03 12-hour format of an hour with leading zeros
1096 H 15 24-hour format of an hour with leading zeros
1097 i 05 Minutes with leading zeros
1098 s 01 Seconds, with leading zeros
1099 O -0600 Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1100 P -06:00 Difference to Greenwich time (GMT) with colon between hours and minutes
1101 T CST Timezone setting of the machine running the code
1102 Z -21600 Timezone offset in seconds (negative if west of UTC, positive if east)
1105 * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1107 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1108 document.write(dt.format('Y-m-d')); //2007-01-10
1109 document.write(dt.format('F j, Y, g:i a')); //January 10, 2007, 3:05 pm
1110 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
1113 * Here are some standard date/time patterns that you might find helpful. They
1114 * are not part of the source of Date.js, but to use them you can simply copy this
1115 * block of code into any script that is included after Date.js and they will also become
1116 * globally available on the Date object. Feel free to add or remove patterns as needed in your code.
1119 ISO8601Long:"Y-m-d H:i:s",
1120 ISO8601Short:"Y-m-d",
1122 LongDate: "l, F d, Y",
1123 FullDateTime: "l, F d, Y g:i:s A",
1126 LongTime: "g:i:s A",
1127 SortableDateTime: "Y-m-d\\TH:i:s",
1128 UniversalSortableDateTime: "Y-m-d H:i:sO",
1135 var dt = new Date();
1136 document.write(dt.format(Date.patterns.ShortDate));
1141 * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1142 * They generate precompiled functions from date formats instead of parsing and
1143 * processing the pattern every time you format a date. These functions are available
1144 * on every Date object (any javascript function).
1146 * The original article and download are here:
1147 * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1154 Returns the number of milliseconds between this date and date
1155 @param {Date} date (optional) Defaults to now
1156 @return {Number} The diff in milliseconds
1157 @member Date getElapsed
1159 Date.prototype.getElapsed = function(date) {
1160 return Math.abs((date || new Date()).getTime()-this.getTime());
1162 // was in date file..
1166 Date.parseFunctions = {count:0};
1168 Date.parseRegexes = [];
1170 Date.formatFunctions = {count:0};
1173 Date.prototype.dateFormat = function(format) {
1174 if (Date.formatFunctions[format] == null) {
1175 Date.createNewFormat(format);
1177 var func = Date.formatFunctions[format];
1178 return this[func]();
1183 * Formats a date given the supplied format string
1184 * @param {String} format The format string
1185 * @return {String} The formatted date
1188 Date.prototype.format = Date.prototype.dateFormat;
1191 Date.createNewFormat = function(format) {
1192 var funcName = "format" + Date.formatFunctions.count++;
1193 Date.formatFunctions[format] = funcName;
1194 var code = "Date.prototype." + funcName + " = function(){return ";
1195 var special = false;
1197 for (var i = 0; i < format.length; ++i) {
1198 ch = format.charAt(i);
1199 if (!special && ch == "\\") {
1204 code += "'" + String.escape(ch) + "' + ";
1207 code += Date.getFormatCode(ch);
1210 /** eval:var:zzzzzzzzzzzzz */
1211 eval(code.substring(0, code.length - 3) + ";}");
1215 Date.getFormatCode = function(character) {
1216 switch (character) {
1218 return "String.leftPad(this.getDate(), 2, '0') + ";
1220 return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1222 return "this.getDate() + ";
1224 return "Date.dayNames[this.getDay()] + ";
1226 return "this.getSuffix() + ";
1228 return "this.getDay() + ";
1230 return "this.getDayOfYear() + ";
1232 return "this.getWeekOfYear() + ";
1234 return "Date.monthNames[this.getMonth()] + ";
1236 return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1238 return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1240 return "(this.getMonth() + 1) + ";
1242 return "this.getDaysInMonth() + ";
1244 return "(this.isLeapYear() ? 1 : 0) + ";
1246 return "this.getFullYear() + ";
1248 return "('' + this.getFullYear()).substring(2, 4) + ";
1250 return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1252 return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1254 return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1256 return "this.getHours() + ";
1258 return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1260 return "String.leftPad(this.getHours(), 2, '0') + ";
1262 return "String.leftPad(this.getMinutes(), 2, '0') + ";
1264 return "String.leftPad(this.getSeconds(), 2, '0') + ";
1266 return "this.getGMTOffset() + ";
1268 return "this.getGMTColonOffset() + ";
1270 return "this.getTimezone() + ";
1272 return "(this.getTimezoneOffset() * -60) + ";
1274 return "'" + String.escape(character) + "' + ";
1279 * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1280 * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates. Any part of
1281 * the date format that is not specified will default to the current date value for that part. Time parts can also
1282 * be specified, but default to 0. Keep in mind that the input date string must precisely match the specified format
1283 * string or the parse operation will fail.
1286 //dt = Fri May 25 2007 (current date)
1287 var dt = new Date();
1289 //dt = Thu May 25 2006 (today's month/day in 2006)
1290 dt = Date.parseDate("2006", "Y");
1292 //dt = Sun Jan 15 2006 (all date parts specified)
1293 dt = Date.parseDate("2006-1-15", "Y-m-d");
1295 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1296 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1298 * @param {String} input The unparsed date as a string
1299 * @param {String} format The format the date is in
1300 * @return {Date} The parsed date
1303 Date.parseDate = function(input, format) {
1304 if (Date.parseFunctions[format] == null) {
1305 Date.createParser(format);
1307 var func = Date.parseFunctions[format];
1308 return Date[func](input);
1314 Date.createParser = function(format) {
1315 var funcName = "parse" + Date.parseFunctions.count++;
1316 var regexNum = Date.parseRegexes.length;
1317 var currentGroup = 1;
1318 Date.parseFunctions[format] = funcName;
1320 var code = "Date." + funcName + " = function(input){\n"
1321 + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1322 + "var d = new Date();\n"
1323 + "y = d.getFullYear();\n"
1324 + "m = d.getMonth();\n"
1325 + "d = d.getDate();\n"
1326 + "if (typeof(input) !== 'string') { input = input.toString(); }\n"
1327 + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1328 + "if (results && results.length > 0) {";
1331 var special = false;
1333 for (var i = 0; i < format.length; ++i) {
1334 ch = format.charAt(i);
1335 if (!special && ch == "\\") {
1340 regex += String.escape(ch);
1343 var obj = Date.formatCodeToRegex(ch, currentGroup);
1344 currentGroup += obj.g;
1346 if (obj.g && obj.c) {
1352 code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1353 + "{v = new Date(y, m, d, h, i, s);}\n"
1354 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1355 + "{v = new Date(y, m, d, h, i);}\n"
1356 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1357 + "{v = new Date(y, m, d, h);}\n"
1358 + "else if (y >= 0 && m >= 0 && d > 0)\n"
1359 + "{v = new Date(y, m, d);}\n"
1360 + "else if (y >= 0 && m >= 0)\n"
1361 + "{v = new Date(y, m);}\n"
1362 + "else if (y >= 0)\n"
1363 + "{v = new Date(y);}\n"
1364 + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1365 + " ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1366 + " v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1369 Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1370 /** eval:var:zzzzzzzzzzzzz */
1375 Date.formatCodeToRegex = function(character, currentGroup) {
1376 switch (character) {
1380 s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1383 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1384 s:"(\\d{1,2})"}; // day of month without leading zeroes
1387 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1388 s:"(\\d{2})"}; // day of month with leading zeroes
1392 s:"(?:" + Date.dayNames.join("|") + ")"};
1396 s:"(?:st|nd|rd|th)"};
1411 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1412 s:"(" + Date.monthNames.join("|") + ")"};
1415 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1416 s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1419 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1420 s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1423 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1424 s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1435 c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1439 c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1440 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1444 c:"if (results[" + currentGroup + "] == 'am') {\n"
1445 + "if (h == 12) { h = 0; }\n"
1446 + "} else { if (h < 12) { h += 12; }}",
1450 c:"if (results[" + currentGroup + "] == 'AM') {\n"
1451 + "if (h == 12) { h = 0; }\n"
1452 + "} else { if (h < 12) { h += 12; }}",
1457 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1458 s:"(\\d{1,2})"}; // 12/24-hr format format of an hour without leading zeroes
1462 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1463 s:"(\\d{2})"}; // 12/24-hr format format of an hour with leading zeroes
1466 c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1470 c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1475 "o = results[", currentGroup, "];\n",
1476 "var sn = o.substring(0,1);\n", // get + / - sign
1477 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1478 "var mn = o.substring(3,5) % 60;\n", // get minutes
1479 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1480 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1482 s:"([+\-]\\d{2,4})"};
1488 "o = results[", currentGroup, "];\n",
1489 "var sn = o.substring(0,1);\n",
1490 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1491 "var mn = o.substring(4,6) % 60;\n",
1492 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1493 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1499 s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1502 c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1503 + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1504 s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1508 s:String.escape(character)};
1513 * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1514 * @return {String} The abbreviated timezone name (e.g. 'CST')
1516 Date.prototype.getTimezone = function() {
1517 return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1521 * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1522 * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1524 Date.prototype.getGMTOffset = function() {
1525 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1526 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1527 + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1531 * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1532 * @return {String} 2-characters representing hours and 2-characters representing minutes
1533 * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1535 Date.prototype.getGMTColonOffset = function() {
1536 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1537 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1539 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1543 * Get the numeric day number of the year, adjusted for leap year.
1544 * @return {Number} 0 through 364 (365 in leap years)
1546 Date.prototype.getDayOfYear = function() {
1548 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1549 for (var i = 0; i < this.getMonth(); ++i) {
1550 num += Date.daysInMonth[i];
1552 return num + this.getDate() - 1;
1556 * Get the string representation of the numeric week number of the year
1557 * (equivalent to the format specifier 'W').
1558 * @return {String} '00' through '52'
1560 Date.prototype.getWeekOfYear = function() {
1561 // Skip to Thursday of this week
1562 var now = this.getDayOfYear() + (4 - this.getDay());
1563 // Find the first Thursday of the year
1564 var jan1 = new Date(this.getFullYear(), 0, 1);
1565 var then = (7 - jan1.getDay() + 4);
1566 return String.leftPad(((now - then) / 7) + 1, 2, "0");
1570 * Whether or not the current date is in a leap year.
1571 * @return {Boolean} True if the current date is in a leap year, else false
1573 Date.prototype.isLeapYear = function() {
1574 var year = this.getFullYear();
1575 return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1579 * Get the first day of the current month, adjusted for leap year. The returned value
1580 * is the numeric day index within the week (0-6) which can be used in conjunction with
1581 * the {@link #monthNames} array to retrieve the textual day name.
1584 var dt = new Date('1/10/2007');
1585 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1587 * @return {Number} The day number (0-6)
1589 Date.prototype.getFirstDayOfMonth = function() {
1590 var day = (this.getDay() - (this.getDate() - 1)) % 7;
1591 return (day < 0) ? (day + 7) : day;
1595 * Get the last day of the current month, adjusted for leap year. The returned value
1596 * is the numeric day index within the week (0-6) which can be used in conjunction with
1597 * the {@link #monthNames} array to retrieve the textual day name.
1600 var dt = new Date('1/10/2007');
1601 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1603 * @return {Number} The day number (0-6)
1605 Date.prototype.getLastDayOfMonth = function() {
1606 var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1607 return (day < 0) ? (day + 7) : day;
1612 * Get the first date of this date's month
1615 Date.prototype.getFirstDateOfMonth = function() {
1616 return new Date(this.getFullYear(), this.getMonth(), 1);
1620 * Get the last date of this date's month
1623 Date.prototype.getLastDateOfMonth = function() {
1624 return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1627 * Get the number of days in the current month, adjusted for leap year.
1628 * @return {Number} The number of days in the month
1630 Date.prototype.getDaysInMonth = function() {
1631 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1632 return Date.daysInMonth[this.getMonth()];
1636 * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1637 * @return {String} 'st, 'nd', 'rd' or 'th'
1639 Date.prototype.getSuffix = function() {
1640 switch (this.getDate()) {
1657 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1660 * An array of textual month names.
1661 * Override these values for international dates, for example...
1662 * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1681 * An array of textual day names.
1682 * Override these values for international dates, for example...
1683 * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1699 Date.monthNumbers = {
1714 * Creates and returns a new Date instance with the exact same date value as the called instance.
1715 * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1716 * variable will also be changed. When the intention is to create a new variable that will not
1717 * modify the original instance, you should create a clone.
1719 * Example of correctly cloning a date:
1722 var orig = new Date('10/1/2006');
1725 document.write(orig); //returns 'Thu Oct 05 2006'!
1728 var orig = new Date('10/1/2006');
1729 var copy = orig.clone();
1731 document.write(orig); //returns 'Thu Oct 01 2006'
1733 * @return {Date} The new Date instance
1735 Date.prototype.clone = function() {
1736 return new Date(this.getTime());
1740 * Clears any time information from this date
1741 @param {Boolean} clone true to create a clone of this date, clear the time and return it
1742 @return {Date} this or the clone
1744 Date.prototype.clearTime = function(clone){
1746 return this.clone().clearTime();
1751 this.setMilliseconds(0);
1756 // safari setMonth is broken -- check that this is only donw once...
1757 if(Roo.isSafari && typeof(Date.brokenSetMonth) == 'undefined'){
1758 Date.brokenSetMonth = Date.prototype.setMonth;
1759 Date.prototype.setMonth = function(num){
1761 var n = Math.ceil(-num);
1762 var back_year = Math.ceil(n/12);
1763 var month = (n % 12) ? 12 - n % 12 : 0 ;
1764 this.setFullYear(this.getFullYear() - back_year);
1765 return Date.brokenSetMonth.call(this, month);
1767 return Date.brokenSetMonth.apply(this, arguments);
1772 /** Date interval constant
1776 /** Date interval constant
1780 /** Date interval constant
1784 /** Date interval constant
1788 /** Date interval constant
1792 /** Date interval constant
1796 /** Date interval constant
1802 * Provides a convenient method of performing basic date arithmetic. This method
1803 * does not modify the Date instance being called - it creates and returns
1804 * a new Date instance containing the resulting date value.
1809 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1810 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1812 //Negative values will subtract correctly:
1813 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1814 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1816 //You can even chain several calls together in one line!
1817 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1818 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1821 * @param {String} interval A valid date interval enum value
1822 * @param {Number} value The amount to add to the current date
1823 * @return {Date} The new Date instance
1825 Date.prototype.add = function(interval, value){
1826 var d = this.clone();
1827 if (!interval || value === 0) { return d; }
1828 switch(interval.toLowerCase()){
1830 d.setMilliseconds(this.getMilliseconds() + value);
1833 d.setSeconds(this.getSeconds() + value);
1836 d.setMinutes(this.getMinutes() + value);
1839 d.setHours(this.getHours() + value);
1842 d.setDate(this.getDate() + value);
1845 var day = this.getDate();
1847 day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1850 d.setMonth(this.getMonth() + value);
1853 d.setFullYear(this.getFullYear() + value);
1860 * Ext JS Library 1.1.1
1861 * Copyright(c) 2006-2007, Ext JS, LLC.
1863 * Originally Released Under LGPL - original licence link has changed is not relivant.
1866 * <script type="text/javascript">
1870 * @class Roo.lib.Dom
1873 * Dom utils (from YIU afaik)
1878 * Get the view width
1879 * @param {Boolean} full True will get the full document, otherwise it's the view width
1880 * @return {Number} The width
1883 getViewWidth : function(full) {
1884 return full ? this.getDocumentWidth() : this.getViewportWidth();
1887 * Get the view height
1888 * @param {Boolean} full True will get the full document, otherwise it's the view height
1889 * @return {Number} The height
1891 getViewHeight : function(full) {
1892 return full ? this.getDocumentHeight() : this.getViewportHeight();
1895 getDocumentHeight: function() {
1896 var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1897 return Math.max(scrollHeight, this.getViewportHeight());
1900 getDocumentWidth: function() {
1901 var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1902 return Math.max(scrollWidth, this.getViewportWidth());
1905 getViewportHeight: function() {
1906 var height = self.innerHeight;
1907 var mode = document.compatMode;
1909 if ((mode || Roo.isIE) && !Roo.isOpera) {
1910 height = (mode == "CSS1Compat") ?
1911 document.documentElement.clientHeight :
1912 document.body.clientHeight;
1918 getViewportWidth: function() {
1919 var width = self.innerWidth;
1920 var mode = document.compatMode;
1922 if (mode || Roo.isIE) {
1923 width = (mode == "CSS1Compat") ?
1924 document.documentElement.clientWidth :
1925 document.body.clientWidth;
1930 isAncestor : function(p, c) {
1937 if (p.contains && !Roo.isSafari) {
1938 return p.contains(c);
1939 } else if (p.compareDocumentPosition) {
1940 return !!(p.compareDocumentPosition(c) & 16);
1942 var parent = c.parentNode;
1947 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1950 parent = parent.parentNode;
1956 getRegion : function(el) {
1957 return Roo.lib.Region.getRegion(el);
1960 getY : function(el) {
1961 return this.getXY(el)[1];
1964 getX : function(el) {
1965 return this.getXY(el)[0];
1968 getXY : function(el) {
1969 var p, pe, b, scroll, bd = document.body;
1970 el = Roo.getDom(el);
1971 var fly = Roo.lib.AnimBase.fly;
1972 if (el.getBoundingClientRect) {
1973 b = el.getBoundingClientRect();
1974 scroll = fly(document).getScroll();
1975 return [b.left + scroll.left, b.top + scroll.top];
1981 var hasAbsolute = fly(el).getStyle("position") == "absolute";
1988 if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1995 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1996 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
2003 if (p != el && pe.getStyle('overflow') != 'visible') {
2011 if (Roo.isSafari && hasAbsolute) {
2016 if (Roo.isGecko && !hasAbsolute) {
2018 x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
2019 y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
2023 while (p && p != bd) {
2024 if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
2036 setXY : function(el, xy) {
2037 el = Roo.fly(el, '_setXY');
2039 var pts = el.translatePoints(xy);
2040 if (xy[0] !== false) {
2041 el.dom.style.left = pts.left + "px";
2043 if (xy[1] !== false) {
2044 el.dom.style.top = pts.top + "px";
2048 setX : function(el, x) {
2049 this.setXY(el, [x, false]);
2052 setY : function(el, y) {
2053 this.setXY(el, [false, y]);
2057 * Portions of this file are based on pieces of Yahoo User Interface Library
2058 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2059 * YUI licensed under the BSD License:
2060 * http://developer.yahoo.net/yui/license.txt
2061 * <script type="text/javascript">
2065 Roo.lib.Event = function() {
2066 var loadComplete = false;
2068 var unloadListeners = [];
2070 var onAvailStack = [];
2072 var lastError = null;
2085 startInterval: function() {
2086 if (!this._interval) {
2088 var callback = function() {
2089 self._tryPreloadAttach();
2091 this._interval = setInterval(callback, this.POLL_INTERVAL);
2096 onAvailable: function(p_id, p_fn, p_obj, p_override) {
2097 onAvailStack.push({ id: p_id,
2100 override: p_override,
2101 checkReady: false });
2103 retryCount = this.POLL_RETRYS;
2104 this.startInterval();
2108 addListener: function(el, eventName, fn) {
2109 el = Roo.getDom(el);
2114 if ("unload" == eventName) {
2115 unloadListeners[unloadListeners.length] =
2116 [el, eventName, fn];
2120 var wrappedFn = function(e) {
2121 return fn(Roo.lib.Event.getEvent(e));
2124 var li = [el, eventName, fn, wrappedFn];
2126 var index = listeners.length;
2127 listeners[index] = li;
2129 this.doAdd(el, eventName, wrappedFn, false);
2135 removeListener: function(el, eventName, fn) {
2138 el = Roo.getDom(el);
2141 return this.purgeElement(el, false, eventName);
2145 if ("unload" == eventName) {
2147 for (i = 0,len = unloadListeners.length; i < len; i++) {
2148 var li = unloadListeners[i];
2151 li[1] == eventName &&
2153 unloadListeners.splice(i, 1);
2161 var cacheItem = null;
2164 var index = arguments[3];
2166 if ("undefined" == typeof index) {
2167 index = this._getCacheIndex(el, eventName, fn);
2171 cacheItem = listeners[index];
2174 if (!el || !cacheItem) {
2178 this.doRemove(el, eventName, cacheItem[this.WFN], false);
2180 delete listeners[index][this.WFN];
2181 delete listeners[index][this.FN];
2182 listeners.splice(index, 1);
2189 getTarget: function(ev, resolveTextNode) {
2190 ev = ev.browserEvent || ev;
2191 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2192 var t = ev.target || ev.srcElement;
2193 return this.resolveTextNode(t);
2197 resolveTextNode: function(node) {
2198 if (Roo.isSafari && node && 3 == node.nodeType) {
2199 return node.parentNode;
2206 getPageX: function(ev) {
2207 ev = ev.browserEvent || ev;
2208 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2210 if (!x && 0 !== x) {
2211 x = ev.clientX || 0;
2214 x += this.getScroll()[1];
2222 getPageY: function(ev) {
2223 ev = ev.browserEvent || ev;
2224 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2226 if (!y && 0 !== y) {
2227 y = ev.clientY || 0;
2230 y += this.getScroll()[0];
2239 getXY: function(ev) {
2240 ev = ev.browserEvent || ev;
2241 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2242 return [this.getPageX(ev), this.getPageY(ev)];
2246 getRelatedTarget: function(ev) {
2247 ev = ev.browserEvent || ev;
2248 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2249 var t = ev.relatedTarget;
2251 if (ev.type == "mouseout") {
2253 } else if (ev.type == "mouseover") {
2258 return this.resolveTextNode(t);
2262 getTime: function(ev) {
2263 ev = ev.browserEvent || ev;
2264 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2266 var t = new Date().getTime();
2270 this.lastError = ex;
2279 stopEvent: function(ev) {
2280 this.stopPropagation(ev);
2281 this.preventDefault(ev);
2285 stopPropagation: function(ev) {
2286 ev = ev.browserEvent || ev;
2287 if (ev.stopPropagation) {
2288 ev.stopPropagation();
2290 ev.cancelBubble = true;
2295 preventDefault: function(ev) {
2296 ev = ev.browserEvent || ev;
2297 if(ev.preventDefault) {
2298 ev.preventDefault();
2300 ev.returnValue = false;
2305 getEvent: function(e) {
2306 var ev = e || window.event;
2308 var c = this.getEvent.caller;
2310 ev = c.arguments[0];
2311 if (ev && Event == ev.constructor) {
2321 getCharCode: function(ev) {
2322 ev = ev.browserEvent || ev;
2323 return ev.charCode || ev.keyCode || 0;
2327 _getCacheIndex: function(el, eventName, fn) {
2328 for (var i = 0,len = listeners.length; i < len; ++i) {
2329 var li = listeners[i];
2331 li[this.FN] == fn &&
2332 li[this.EL] == el &&
2333 li[this.TYPE] == eventName) {
2345 getEl: function(id) {
2346 return document.getElementById(id);
2350 clearCache: function() {
2354 _load: function(e) {
2355 loadComplete = true;
2356 var EU = Roo.lib.Event;
2360 EU.doRemove(window, "load", EU._load);
2365 _tryPreloadAttach: function() {
2374 var tryAgain = !loadComplete;
2376 tryAgain = (retryCount > 0);
2381 for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2382 var item = onAvailStack[i];
2384 var el = this.getEl(item.id);
2387 if (!item.checkReady ||
2390 (document && document.body)) {
2393 if (item.override) {
2394 if (item.override === true) {
2397 scope = item.override;
2400 item.fn.call(scope, item.obj);
2401 onAvailStack[i] = null;
2404 notAvail.push(item);
2409 retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2413 this.startInterval();
2415 clearInterval(this._interval);
2416 this._interval = null;
2419 this.locked = false;
2426 purgeElement: function(el, recurse, eventName) {
2427 var elListeners = this.getListeners(el, eventName);
2429 for (var i = 0,len = elListeners.length; i < len; ++i) {
2430 var l = elListeners[i];
2431 this.removeListener(el, l.type, l.fn);
2435 if (recurse && el && el.childNodes) {
2436 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2437 this.purgeElement(el.childNodes[i], recurse, eventName);
2443 getListeners: function(el, eventName) {
2444 var results = [], searchLists;
2446 searchLists = [listeners, unloadListeners];
2447 } else if (eventName == "unload") {
2448 searchLists = [unloadListeners];
2450 searchLists = [listeners];
2453 for (var j = 0; j < searchLists.length; ++j) {
2454 var searchList = searchLists[j];
2455 if (searchList && searchList.length > 0) {
2456 for (var i = 0,len = searchList.length; i < len; ++i) {
2457 var l = searchList[i];
2458 if (l && l[this.EL] === el &&
2459 (!eventName || eventName === l[this.TYPE])) {
2464 adjust: l[this.ADJ_SCOPE],
2472 return (results.length) ? results : null;
2476 _unload: function(e) {
2478 var EU = Roo.lib.Event, i, j, l, len, index;
2480 for (i = 0,len = unloadListeners.length; i < len; ++i) {
2481 l = unloadListeners[i];
2484 if (l[EU.ADJ_SCOPE]) {
2485 if (l[EU.ADJ_SCOPE] === true) {
2488 scope = l[EU.ADJ_SCOPE];
2491 l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2492 unloadListeners[i] = null;
2498 unloadListeners = null;
2500 if (listeners && listeners.length > 0) {
2501 j = listeners.length;
2504 l = listeners[index];
2506 EU.removeListener(l[EU.EL], l[EU.TYPE],
2516 EU.doRemove(window, "unload", EU._unload);
2521 getScroll: function() {
2522 var dd = document.documentElement, db = document.body;
2523 if (dd && (dd.scrollTop || dd.scrollLeft)) {
2524 return [dd.scrollTop, dd.scrollLeft];
2526 return [db.scrollTop, db.scrollLeft];
2533 doAdd: function () {
2534 if (window.addEventListener) {
2535 return function(el, eventName, fn, capture) {
2536 el.addEventListener(eventName, fn, (capture));
2538 } else if (window.attachEvent) {
2539 return function(el, eventName, fn, capture) {
2540 el.attachEvent("on" + eventName, fn);
2549 doRemove: function() {
2550 if (window.removeEventListener) {
2551 return function (el, eventName, fn, capture) {
2552 el.removeEventListener(eventName, fn, (capture));
2554 } else if (window.detachEvent) {
2555 return function (el, eventName, fn) {
2556 el.detachEvent("on" + eventName, fn);
2568 var E = Roo.lib.Event;
2569 E.on = E.addListener;
2570 E.un = E.removeListener;
2572 if (document && document.body) {
2575 E.doAdd(window, "load", E._load);
2577 E.doAdd(window, "unload", E._unload);
2578 E._tryPreloadAttach();
2582 * Portions of this file are based on pieces of Yahoo User Interface Library
2583 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2584 * YUI licensed under the BSD License:
2585 * http://developer.yahoo.net/yui/license.txt
2586 * <script type="text/javascript">
2592 * @class Roo.lib.Ajax
2599 request : function(method, uri, cb, data, options) {
2601 var hs = options.headers;
2604 if(hs.hasOwnProperty(h)){
2605 this.initHeader(h, hs[h], false);
2609 if(options.xmlData){
2610 this.initHeader('Content-Type', 'text/xml', false);
2612 data = options.xmlData;
2616 return this.asyncRequest(method, uri, cb, data);
2619 serializeForm : function(form) {
2620 if(typeof form == 'string') {
2621 form = (document.getElementById(form) || document.forms[form]);
2624 var el, name, val, disabled, data = '', hasSubmit = false;
2625 for (var i = 0; i < form.elements.length; i++) {
2626 el = form.elements[i];
2627 disabled = form.elements[i].disabled;
2628 name = form.elements[i].name;
2629 val = form.elements[i].value;
2631 if (!disabled && name){
2635 case 'select-multiple':
2636 for (var j = 0; j < el.options.length; j++) {
2637 if (el.options[j].selected) {
2639 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2642 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2650 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2663 if(hasSubmit == false) {
2664 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2669 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2674 data = data.substr(0, data.length - 1);
2682 useDefaultHeader:true,
2684 defaultPostHeader:'application/x-www-form-urlencoded',
2686 useDefaultXhrHeader:true,
2688 defaultXhrHeader:'XMLHttpRequest',
2690 hasDefaultHeaders:true,
2702 setProgId:function(id)
2704 this.activeX.unshift(id);
2707 setDefaultPostHeader:function(b)
2709 this.useDefaultHeader = b;
2712 setDefaultXhrHeader:function(b)
2714 this.useDefaultXhrHeader = b;
2717 setPollingInterval:function(i)
2719 if (typeof i == 'number' && isFinite(i)) {
2720 this.pollInterval = i;
2724 createXhrObject:function(transactionId)
2730 http = new XMLHttpRequest();
2732 obj = { conn:http, tId:transactionId };
2736 for (var i = 0; i < this.activeX.length; ++i) {
2740 http = new ActiveXObject(this.activeX[i]);
2742 obj = { conn:http, tId:transactionId };
2755 getConnectionObject:function()
2758 var tId = this.transactionId;
2762 o = this.createXhrObject(tId);
2764 this.transactionId++;
2775 asyncRequest:function(method, uri, callback, postData)
2777 var o = this.getConnectionObject();
2783 o.conn.open(method, uri, true);
2785 if (this.useDefaultXhrHeader) {
2786 if (!this.defaultHeaders['X-Requested-With']) {
2787 this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2791 if(postData && this.useDefaultHeader){
2792 this.initHeader('Content-Type', this.defaultPostHeader);
2795 if (this.hasDefaultHeaders || this.hasHeaders) {
2799 this.handleReadyState(o, callback);
2800 o.conn.send(postData || null);
2806 handleReadyState:function(o, callback)
2810 if (callback && callback.timeout) {
2812 this.timeout[o.tId] = window.setTimeout(function() {
2813 oConn.abort(o, callback, true);
2814 }, callback.timeout);
2817 this.poll[o.tId] = window.setInterval(
2819 if (o.conn && o.conn.readyState == 4) {
2820 window.clearInterval(oConn.poll[o.tId]);
2821 delete oConn.poll[o.tId];
2823 if(callback && callback.timeout) {
2824 window.clearTimeout(oConn.timeout[o.tId]);
2825 delete oConn.timeout[o.tId];
2828 oConn.handleTransactionResponse(o, callback);
2831 , this.pollInterval);
2834 handleTransactionResponse:function(o, callback, isAbort)
2838 this.releaseObject(o);
2842 var httpStatus, responseObject;
2846 if (o.conn.status !== undefined && o.conn.status != 0) {
2847 httpStatus = o.conn.status;
2859 if (httpStatus >= 200 && httpStatus < 300) {
2860 responseObject = this.createResponseObject(o, callback.argument);
2861 if (callback.success) {
2862 if (!callback.scope) {
2863 callback.success(responseObject);
2868 callback.success.apply(callback.scope, [responseObject]);
2873 switch (httpStatus) {
2881 responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2882 if (callback.failure) {
2883 if (!callback.scope) {
2884 callback.failure(responseObject);
2887 callback.failure.apply(callback.scope, [responseObject]);
2892 responseObject = this.createResponseObject(o, callback.argument);
2893 if (callback.failure) {
2894 if (!callback.scope) {
2895 callback.failure(responseObject);
2898 callback.failure.apply(callback.scope, [responseObject]);
2904 this.releaseObject(o);
2905 responseObject = null;
2908 createResponseObject:function(o, callbackArg)
2915 var headerStr = o.conn.getAllResponseHeaders();
2916 var header = headerStr.split('\n');
2917 for (var i = 0; i < header.length; i++) {
2918 var delimitPos = header[i].indexOf(':');
2919 if (delimitPos != -1) {
2920 headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2928 obj.status = o.conn.status;
2929 obj.statusText = o.conn.statusText;
2930 obj.getResponseHeader = headerObj;
2931 obj.getAllResponseHeaders = headerStr;
2932 obj.responseText = o.conn.responseText;
2933 obj.responseXML = o.conn.responseXML;
2935 if (typeof callbackArg !== undefined) {
2936 obj.argument = callbackArg;
2942 createExceptionObject:function(tId, callbackArg, isAbort)
2945 var COMM_ERROR = 'communication failure';
2946 var ABORT_CODE = -1;
2947 var ABORT_ERROR = 'transaction aborted';
2953 obj.status = ABORT_CODE;
2954 obj.statusText = ABORT_ERROR;
2957 obj.status = COMM_CODE;
2958 obj.statusText = COMM_ERROR;
2962 obj.argument = callbackArg;
2968 initHeader:function(label, value, isDefault)
2970 var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2972 if (headerObj[label] === undefined) {
2973 headerObj[label] = value;
2978 headerObj[label] = value + "," + headerObj[label];
2982 this.hasDefaultHeaders = true;
2985 this.hasHeaders = true;
2990 setHeader:function(o)
2992 if (this.hasDefaultHeaders) {
2993 for (var prop in this.defaultHeaders) {
2994 if (this.defaultHeaders.hasOwnProperty(prop)) {
2995 o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
3000 if (this.hasHeaders) {
3001 for (var prop in this.headers) {
3002 if (this.headers.hasOwnProperty(prop)) {
3003 o.conn.setRequestHeader(prop, this.headers[prop]);
3007 this.hasHeaders = false;
3011 resetDefaultHeaders:function() {
3012 delete this.defaultHeaders;
3013 this.defaultHeaders = {};
3014 this.hasDefaultHeaders = false;
3017 abort:function(o, callback, isTimeout)
3019 if(this.isCallInProgress(o)) {
3021 window.clearInterval(this.poll[o.tId]);
3022 delete this.poll[o.tId];
3024 delete this.timeout[o.tId];
3027 this.handleTransactionResponse(o, callback, true);
3037 isCallInProgress:function(o)
3040 return o.conn.readyState != 4 && o.conn.readyState != 0;
3049 releaseObject:function(o)
3058 'MSXML2.XMLHTTP.3.0',
3066 * Portions of this file are based on pieces of Yahoo User Interface Library
3067 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3068 * YUI licensed under the BSD License:
3069 * http://developer.yahoo.net/yui/license.txt
3070 * <script type="text/javascript">
3074 Roo.lib.Region = function(t, r, b, l) {
3084 Roo.lib.Region.prototype = {
3085 contains : function(region) {
3086 return ( region.left >= this.left &&
3087 region.right <= this.right &&
3088 region.top >= this.top &&
3089 region.bottom <= this.bottom );
3093 getArea : function() {
3094 return ( (this.bottom - this.top) * (this.right - this.left) );
3097 intersect : function(region) {
3098 var t = Math.max(this.top, region.top);
3099 var r = Math.min(this.right, region.right);
3100 var b = Math.min(this.bottom, region.bottom);
3101 var l = Math.max(this.left, region.left);
3103 if (b >= t && r >= l) {
3104 return new Roo.lib.Region(t, r, b, l);
3109 union : function(region) {
3110 var t = Math.min(this.top, region.top);
3111 var r = Math.max(this.right, region.right);
3112 var b = Math.max(this.bottom, region.bottom);
3113 var l = Math.min(this.left, region.left);
3115 return new Roo.lib.Region(t, r, b, l);
3118 adjust : function(t, l, b, r) {
3127 Roo.lib.Region.getRegion = function(el) {
3128 var p = Roo.lib.Dom.getXY(el);
3131 var r = p[0] + el.offsetWidth;
3132 var b = p[1] + el.offsetHeight;
3135 return new Roo.lib.Region(t, r, b, l);
3138 * Portions of this file are based on pieces of Yahoo User Interface Library
3139 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3140 * YUI licensed under the BSD License:
3141 * http://developer.yahoo.net/yui/license.txt
3142 * <script type="text/javascript">
3145 //@@dep Roo.lib.Region
3148 Roo.lib.Point = function(x, y) {
3149 if (x instanceof Array) {
3153 this.x = this.right = this.left = this[0] = x;
3154 this.y = this.top = this.bottom = this[1] = y;
3157 Roo.lib.Point.prototype = new Roo.lib.Region();
3159 * Portions of this file are based on pieces of Yahoo User Interface Library
3160 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3161 * YUI licensed under the BSD License:
3162 * http://developer.yahoo.net/yui/license.txt
3163 * <script type="text/javascript">
3170 scroll : function(el, args, duration, easing, cb, scope) {
3171 this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3174 motion : function(el, args, duration, easing, cb, scope) {
3175 this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3178 color : function(el, args, duration, easing, cb, scope) {
3179 this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3182 run : function(el, args, duration, easing, cb, scope, type) {
3183 type = type || Roo.lib.AnimBase;
3184 if (typeof easing == "string") {
3185 easing = Roo.lib.Easing[easing];
3187 var anim = new type(el, args, duration, easing);
3188 anim.animateX(function() {
3189 Roo.callback(cb, scope);
3195 * Portions of this file are based on pieces of Yahoo User Interface Library
3196 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3197 * YUI licensed under the BSD License:
3198 * http://developer.yahoo.net/yui/license.txt
3199 * <script type="text/javascript">
3207 if (!libFlyweight) {
3208 libFlyweight = new Roo.Element.Flyweight();
3210 libFlyweight.dom = el;
3211 return libFlyweight;
3214 // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3218 Roo.lib.AnimBase = function(el, attributes, duration, method) {
3220 this.init(el, attributes, duration, method);
3224 Roo.lib.AnimBase.fly = fly;
3228 Roo.lib.AnimBase.prototype = {
3230 toString: function() {
3231 var el = this.getEl();
3232 var id = el.id || el.tagName;
3233 return ("Anim " + id);
3237 noNegatives: /width|height|opacity|padding/i,
3238 offsetAttribute: /^((width|height)|(top|left))$/,
3239 defaultUnit: /width|height|top$|bottom$|left$|right$/i,
3240 offsetUnit: /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3244 doMethod: function(attr, start, end) {
3245 return this.method(this.currentFrame, start, end - start, this.totalFrames);
3249 setAttribute: function(attr, val, unit) {
3250 if (this.patterns.noNegatives.test(attr)) {
3251 val = (val > 0) ? val : 0;
3254 Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3258 getAttribute: function(attr) {
3259 var el = this.getEl();
3260 var val = fly(el).getStyle(attr);
3262 if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3263 return parseFloat(val);
3266 var a = this.patterns.offsetAttribute.exec(attr) || [];
3267 var pos = !!( a[3] );
3268 var box = !!( a[2] );
3271 if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3272 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3281 getDefaultUnit: function(attr) {
3282 if (this.patterns.defaultUnit.test(attr)) {
3289 animateX : function(callback, scope) {
3290 var f = function() {
3291 this.onComplete.removeListener(f);
3292 if (typeof callback == "function") {
3293 callback.call(scope || this, this);
3296 this.onComplete.addListener(f, this);
3301 setRuntimeAttribute: function(attr) {
3304 var attributes = this.attributes;
3306 this.runtimeAttributes[attr] = {};
3308 var isset = function(prop) {
3309 return (typeof prop !== 'undefined');
3312 if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3316 start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3319 if (isset(attributes[attr]['to'])) {
3320 end = attributes[attr]['to'];
3321 } else if (isset(attributes[attr]['by'])) {
3322 if (start.constructor == Array) {
3324 for (var i = 0, len = start.length; i < len; ++i) {
3325 end[i] = start[i] + attributes[attr]['by'][i];
3328 end = start + attributes[attr]['by'];
3332 this.runtimeAttributes[attr].start = start;
3333 this.runtimeAttributes[attr].end = end;
3336 this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3340 init: function(el, attributes, duration, method) {
3342 var isAnimated = false;
3345 var startTime = null;
3348 var actualFrames = 0;
3351 el = Roo.getDom(el);
3354 this.attributes = attributes || {};
3357 this.duration = duration || 1;
3360 this.method = method || Roo.lib.Easing.easeNone;
3363 this.useSeconds = true;
3366 this.currentFrame = 0;
3369 this.totalFrames = Roo.lib.AnimMgr.fps;
3372 this.getEl = function() {
3377 this.isAnimated = function() {
3382 this.getStartTime = function() {
3386 this.runtimeAttributes = {};
3389 this.animate = function() {
3390 if (this.isAnimated()) {
3394 this.currentFrame = 0;
3396 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3398 Roo.lib.AnimMgr.registerElement(this);
3402 this.stop = function(finish) {
3404 this.currentFrame = this.totalFrames;
3405 this._onTween.fire();
3407 Roo.lib.AnimMgr.stop(this);
3410 var onStart = function() {
3411 this.onStart.fire();
3413 this.runtimeAttributes = {};
3414 for (var attr in this.attributes) {
3415 this.setRuntimeAttribute(attr);
3420 startTime = new Date();
3424 var onTween = function() {
3426 duration: new Date() - this.getStartTime(),
3427 currentFrame: this.currentFrame
3430 data.toString = function() {
3432 'duration: ' + data.duration +
3433 ', currentFrame: ' + data.currentFrame
3437 this.onTween.fire(data);
3439 var runtimeAttributes = this.runtimeAttributes;
3441 for (var attr in runtimeAttributes) {
3442 this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3448 var onComplete = function() {
3449 var actual_duration = (new Date() - startTime) / 1000 ;
3452 duration: actual_duration,
3453 frames: actualFrames,
3454 fps: actualFrames / actual_duration
3457 data.toString = function() {
3459 'duration: ' + data.duration +
3460 ', frames: ' + data.frames +
3461 ', fps: ' + data.fps
3467 this.onComplete.fire(data);
3471 this._onStart = new Roo.util.Event(this);
3472 this.onStart = new Roo.util.Event(this);
3473 this.onTween = new Roo.util.Event(this);
3474 this._onTween = new Roo.util.Event(this);
3475 this.onComplete = new Roo.util.Event(this);
3476 this._onComplete = new Roo.util.Event(this);
3477 this._onStart.addListener(onStart);
3478 this._onTween.addListener(onTween);
3479 this._onComplete.addListener(onComplete);
3484 * Portions of this file are based on pieces of Yahoo User Interface Library
3485 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3486 * YUI licensed under the BSD License:
3487 * http://developer.yahoo.net/yui/license.txt
3488 * <script type="text/javascript">
3492 Roo.lib.AnimMgr = new function() {
3509 this.registerElement = function(tween) {
3510 queue[queue.length] = tween;
3512 tween._onStart.fire();
3517 this.unRegister = function(tween, index) {
3518 tween._onComplete.fire();
3519 index = index || getIndex(tween);
3521 queue.splice(index, 1);
3525 if (tweenCount <= 0) {
3531 this.start = function() {
3532 if (thread === null) {
3533 thread = setInterval(this.run, this.delay);
3538 this.stop = function(tween) {
3540 clearInterval(thread);
3542 for (var i = 0, len = queue.length; i < len; ++i) {
3543 if (queue[0].isAnimated()) {
3544 this.unRegister(queue[0], 0);
3553 this.unRegister(tween);
3558 this.run = function() {
3559 for (var i = 0, len = queue.length; i < len; ++i) {
3560 var tween = queue[i];
3561 if (!tween || !tween.isAnimated()) {
3565 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3567 tween.currentFrame += 1;
3569 if (tween.useSeconds) {
3570 correctFrame(tween);
3572 tween._onTween.fire();
3575 Roo.lib.AnimMgr.stop(tween, i);
3580 var getIndex = function(anim) {
3581 for (var i = 0, len = queue.length; i < len; ++i) {
3582 if (queue[i] == anim) {
3590 var correctFrame = function(tween) {
3591 var frames = tween.totalFrames;
3592 var frame = tween.currentFrame;
3593 var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3594 var elapsed = (new Date() - tween.getStartTime());
3597 if (elapsed < tween.duration * 1000) {
3598 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3600 tweak = frames - (frame + 1);
3602 if (tweak > 0 && isFinite(tweak)) {
3603 if (tween.currentFrame + tweak >= frames) {
3604 tweak = frames - (frame + 1);
3607 tween.currentFrame += tweak;
3613 * Portions of this file are based on pieces of Yahoo User Interface Library
3614 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3615 * YUI licensed under the BSD License:
3616 * http://developer.yahoo.net/yui/license.txt
3617 * <script type="text/javascript">
3620 Roo.lib.Bezier = new function() {
3622 this.getPosition = function(points, t) {
3623 var n = points.length;
3626 for (var i = 0; i < n; ++i) {
3627 tmp[i] = [points[i][0], points[i][1]];
3630 for (var j = 1; j < n; ++j) {
3631 for (i = 0; i < n - j; ++i) {
3632 tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3633 tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3637 return [ tmp[0][0], tmp[0][1] ];
3641 * Portions of this file are based on pieces of Yahoo User Interface Library
3642 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3643 * YUI licensed under the BSD License:
3644 * http://developer.yahoo.net/yui/license.txt
3645 * <script type="text/javascript">
3650 Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3651 Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3654 Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3656 var fly = Roo.lib.AnimBase.fly;
3658 var superclass = Y.ColorAnim.superclass;
3659 var proto = Y.ColorAnim.prototype;
3661 proto.toString = function() {
3662 var el = this.getEl();
3663 var id = el.id || el.tagName;
3664 return ("ColorAnim " + id);
3667 proto.patterns.color = /color$/i;
3668 proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3669 proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3670 proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3671 proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3674 proto.parseColor = function(s) {
3675 if (s.length == 3) {
3679 var c = this.patterns.hex.exec(s);
3680 if (c && c.length == 4) {
3681 return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3684 c = this.patterns.rgb.exec(s);
3685 if (c && c.length == 4) {
3686 return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3689 c = this.patterns.hex3.exec(s);
3690 if (c && c.length == 4) {
3691 return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3696 // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3697 proto.getAttribute = function(attr) {
3698 var el = this.getEl();
3699 if (this.patterns.color.test(attr)) {
3700 var val = fly(el).getStyle(attr);
3702 if (this.patterns.transparent.test(val)) {
3703 var parent = el.parentNode;
3704 val = fly(parent).getStyle(attr);
3706 while (parent && this.patterns.transparent.test(val)) {
3707 parent = parent.parentNode;
3708 val = fly(parent).getStyle(attr);
3709 if (parent.tagName.toUpperCase() == 'HTML') {
3715 val = superclass.getAttribute.call(this, attr);
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);
3744 proto.doMethod = function(attr, start, end) {
3747 if (this.patterns.color.test(attr)) {
3749 for (var i = 0, len = start.length; i < len; ++i) {
3750 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3753 val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3756 val = superclass.doMethod.call(this, attr, start, end);
3762 proto.setRuntimeAttribute = function(attr) {
3763 superclass.setRuntimeAttribute.call(this, attr);
3765 if (this.patterns.color.test(attr)) {
3766 var attributes = this.attributes;
3767 var start = this.parseColor(this.runtimeAttributes[attr].start);
3768 var end = this.parseColor(this.runtimeAttributes[attr].end);
3770 if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3771 end = this.parseColor(attributes[attr].by);
3773 for (var i = 0, len = start.length; i < len; ++i) {
3774 end[i] = start[i] + end[i];
3778 this.runtimeAttributes[attr].start = start;
3779 this.runtimeAttributes[attr].end = end;
3785 * Portions of this file are based on pieces of Yahoo User Interface Library
3786 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3787 * YUI licensed under the BSD License:
3788 * http://developer.yahoo.net/yui/license.txt
3789 * <script type="text/javascript">
3795 easeNone: function (t, b, c, d) {
3796 return c * t / d + b;
3800 easeIn: function (t, b, c, d) {
3801 return c * (t /= d) * t + b;
3805 easeOut: function (t, b, c, d) {
3806 return -c * (t /= d) * (t - 2) + b;
3810 easeBoth: function (t, b, c, d) {
3811 if ((t /= d / 2) < 1) {
3812 return c / 2 * t * t + b;
3815 return -c / 2 * ((--t) * (t - 2) - 1) + b;
3819 easeInStrong: function (t, b, c, d) {
3820 return c * (t /= d) * t * t * t + b;
3824 easeOutStrong: function (t, b, c, d) {
3825 return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3829 easeBothStrong: function (t, b, c, d) {
3830 if ((t /= d / 2) < 1) {
3831 return c / 2 * t * t * t * t + b;
3834 return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3839 elasticIn: function (t, b, c, d, a, p) {
3843 if ((t /= d) == 1) {
3850 if (!a || a < Math.abs(c)) {
3855 var s = p / (2 * Math.PI) * Math.asin(c / a);
3858 return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3862 elasticOut: 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) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3885 elasticBoth: function (t, b, c, d, a, p) {
3890 if ((t /= d / 2) == 2) {
3898 if (!a || a < Math.abs(c)) {
3903 var s = p / (2 * Math.PI) * Math.asin(c / a);
3907 return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3908 Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3910 return a * Math.pow(2, -10 * (t -= 1)) *
3911 Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3916 backIn: function (t, b, c, d, s) {
3917 if (typeof s == 'undefined') {
3920 return c * (t /= d) * t * ((s + 1) * t - s) + b;
3924 backOut: function (t, b, c, d, s) {
3925 if (typeof s == 'undefined') {
3928 return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3932 backBoth: function (t, b, c, d, s) {
3933 if (typeof s == 'undefined') {
3937 if ((t /= d / 2 ) < 1) {
3938 return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3940 return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3944 bounceIn: function (t, b, c, d) {
3945 return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3949 bounceOut: function (t, b, c, d) {
3950 if ((t /= d) < (1 / 2.75)) {
3951 return c * (7.5625 * t * t) + b;
3952 } else if (t < (2 / 2.75)) {
3953 return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3954 } else if (t < (2.5 / 2.75)) {
3955 return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3957 return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3961 bounceBoth: function (t, b, c, d) {
3963 return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3965 return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3968 * Portions of this file are based on pieces of Yahoo User Interface Library
3969 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3970 * YUI licensed under the BSD License:
3971 * http://developer.yahoo.net/yui/license.txt
3972 * <script type="text/javascript">
3976 Roo.lib.Motion = function(el, attributes, duration, method) {
3978 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3982 Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3986 var superclass = Y.Motion.superclass;
3987 var proto = Y.Motion.prototype;
3989 proto.toString = function() {
3990 var el = this.getEl();
3991 var id = el.id || el.tagName;
3992 return ("Motion " + id);
3995 proto.patterns.points = /^points$/i;
3997 proto.setAttribute = function(attr, val, unit) {
3998 if (this.patterns.points.test(attr)) {
3999 unit = unit || 'px';
4000 superclass.setAttribute.call(this, 'left', val[0], unit);
4001 superclass.setAttribute.call(this, 'top', val[1], unit);
4003 superclass.setAttribute.call(this, attr, val, unit);
4007 proto.getAttribute = function(attr) {
4008 if (this.patterns.points.test(attr)) {
4010 superclass.getAttribute.call(this, 'left'),
4011 superclass.getAttribute.call(this, 'top')
4014 val = superclass.getAttribute.call(this, attr);
4020 proto.doMethod = function(attr, start, end) {
4023 if (this.patterns.points.test(attr)) {
4024 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
4025 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
4027 val = superclass.doMethod.call(this, attr, start, end);
4032 proto.setRuntimeAttribute = function(attr) {
4033 if (this.patterns.points.test(attr)) {
4034 var el = this.getEl();
4035 var attributes = this.attributes;
4037 var control = attributes['points']['control'] || [];
4041 if (control.length > 0 && !(control[0] instanceof Array)) {
4042 control = [control];
4045 for (i = 0,len = control.length; i < len; ++i) {
4046 tmp[i] = control[i];
4051 Roo.fly(el).position();
4053 if (isset(attributes['points']['from'])) {
4054 Roo.lib.Dom.setXY(el, attributes['points']['from']);
4057 Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
4060 start = this.getAttribute('points');
4063 if (isset(attributes['points']['to'])) {
4064 end = translateValues.call(this, attributes['points']['to'], start);
4066 var pageXY = Roo.lib.Dom.getXY(this.getEl());
4067 for (i = 0,len = control.length; i < len; ++i) {
4068 control[i] = translateValues.call(this, control[i], start);
4072 } else if (isset(attributes['points']['by'])) {
4073 end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
4075 for (i = 0,len = control.length; i < len; ++i) {
4076 control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
4080 this.runtimeAttributes[attr] = [start];
4082 if (control.length > 0) {
4083 this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
4086 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
4089 superclass.setRuntimeAttribute.call(this, attr);
4093 var translateValues = function(val, start) {
4094 var pageXY = Roo.lib.Dom.getXY(this.getEl());
4095 val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4100 var isset = function(prop) {
4101 return (typeof prop !== 'undefined');
4105 * Portions of this file are based on pieces of Yahoo User Interface Library
4106 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4107 * YUI licensed under the BSD License:
4108 * http://developer.yahoo.net/yui/license.txt
4109 * <script type="text/javascript">
4113 Roo.lib.Scroll = function(el, attributes, duration, method) {
4115 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4119 Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4123 var superclass = Y.Scroll.superclass;
4124 var proto = Y.Scroll.prototype;
4126 proto.toString = function() {
4127 var el = this.getEl();
4128 var id = el.id || el.tagName;
4129 return ("Scroll " + id);
4132 proto.doMethod = function(attr, start, end) {
4135 if (attr == 'scroll') {
4137 this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4138 this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4142 val = superclass.doMethod.call(this, attr, start, end);
4147 proto.getAttribute = function(attr) {
4149 var el = this.getEl();
4151 if (attr == 'scroll') {
4152 val = [ el.scrollLeft, el.scrollTop ];
4154 val = superclass.getAttribute.call(this, attr);
4160 proto.setAttribute = function(attr, val, unit) {
4161 var el = this.getEl();
4163 if (attr == 'scroll') {
4164 el.scrollLeft = val[0];
4165 el.scrollTop = val[1];
4167 superclass.setAttribute.call(this, attr, val, unit);
4173 * Ext JS Library 1.1.1
4174 * Copyright(c) 2006-2007, Ext JS, LLC.
4176 * Originally Released Under LGPL - original licence link has changed is not relivant.
4179 * <script type="text/javascript">
4183 // nasty IE9 hack - what a pile of crap that is..
4185 if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4186 Range.prototype.createContextualFragment = function (html) {
4187 var doc = window.document;
4188 var container = doc.createElement("div");
4189 container.innerHTML = html;
4190 var frag = doc.createDocumentFragment(), n;
4191 while ((n = container.firstChild)) {
4192 frag.appendChild(n);
4199 * @class Roo.DomHelper
4200 * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4201 * 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>.
4204 Roo.DomHelper = function(){
4205 var tempTableEl = null;
4206 var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4207 var tableRe = /^table|tbody|tr|td$/i;
4209 // build as innerHTML where available
4211 var createHtml = function(o){
4212 if(typeof o == 'string'){
4221 if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") { continue; }
4222 if(attr == "style"){
4224 if(typeof s == "function"){
4227 if(typeof s == "string"){
4228 b += ' style="' + s + '"';
4229 }else if(typeof s == "object"){
4232 if(typeof s[key] != "function"){
4233 b += key + ":" + s[key] + ";";
4240 b += ' class="' + o["cls"] + '"';
4241 }else if(attr == "htmlFor"){
4242 b += ' for="' + o["htmlFor"] + '"';
4244 b += " " + attr + '="' + o[attr] + '"';
4248 if(emptyTags.test(o.tag)){
4252 var cn = o.children || o.cn;
4254 //http://bugs.kde.org/show_bug.cgi?id=71506
4255 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4256 for(var i = 0, len = cn.length; i < len; i++) {
4257 b += createHtml(cn[i], b);
4260 b += createHtml(cn, b);
4266 b += "</" + o.tag + ">";
4273 var createDom = function(o, parentNode){
4275 // defininition craeted..
4277 if (o.ns && o.ns != 'html') {
4279 if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4280 xmlns[o.ns] = o.xmlns;
4283 if (typeof(xmlns[o.ns]) == 'undefined') {
4284 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4290 if (typeof(o) == 'string') {
4291 return parentNode.appendChild(document.createTextNode(o));
4293 o.tag = o.tag || div;
4294 if (o.ns && Roo.isIE) {
4296 o.tag = o.ns + ':' + o.tag;
4299 var el = ns ? document.createElementNS( ns, o.tag||'div') : document.createElement(o.tag||'div');
4300 var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4303 if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" ||
4304 attr == "style" || typeof o[attr] == "function") { continue; }
4306 if(attr=="cls" && Roo.isIE){
4307 el.className = o["cls"];
4309 if(useSet) { el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);}
4315 Roo.DomHelper.applyStyles(el, o.style);
4316 var cn = o.children || o.cn;
4318 //http://bugs.kde.org/show_bug.cgi?id=71506
4319 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4320 for(var i = 0, len = cn.length; i < len; i++) {
4321 createDom(cn[i], el);
4328 el.innerHTML = o.html;
4331 parentNode.appendChild(el);
4336 var ieTable = function(depth, s, h, e){
4337 tempTableEl.innerHTML = [s, h, e].join('');
4338 var i = -1, el = tempTableEl;
4345 // kill repeat to save bytes
4349 tbe = '</tbody>'+te,
4355 * Nasty code for IE's broken table implementation
4357 var insertIntoTable = function(tag, where, el, html){
4359 tempTableEl = document.createElement('div');
4364 if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4367 if(where == 'beforebegin'){
4371 before = el.nextSibling;
4374 node = ieTable(4, trs, html, tre);
4376 else if(tag == 'tr'){
4377 if(where == 'beforebegin'){
4380 node = ieTable(3, tbs, html, tbe);
4381 } else if(where == 'afterend'){
4382 before = el.nextSibling;
4384 node = ieTable(3, tbs, html, tbe);
4385 } else{ // INTO a TR
4386 if(where == 'afterbegin'){
4387 before = el.firstChild;
4389 node = ieTable(4, trs, html, tre);
4391 } else if(tag == 'tbody'){
4392 if(where == 'beforebegin'){
4395 node = ieTable(2, ts, html, te);
4396 } else if(where == 'afterend'){
4397 before = el.nextSibling;
4399 node = ieTable(2, ts, html, te);
4401 if(where == 'afterbegin'){
4402 before = el.firstChild;
4404 node = ieTable(3, tbs, html, tbe);
4407 if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4410 if(where == 'afterbegin'){
4411 before = el.firstChild;
4413 node = ieTable(2, ts, html, te);
4415 el.insertBefore(node, before);
4420 /** True to force the use of DOM instead of html fragments @type Boolean */
4424 * Returns the markup for the passed Element(s) config
4425 * @param {Object} o The Dom object spec (and children)
4428 markup : function(o){
4429 return createHtml(o);
4433 * Applies a style specification to an element
4434 * @param {String/HTMLElement} el The element to apply styles to
4435 * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4436 * a function which returns such a specification.
4438 applyStyles : function(el, styles){
4441 if(typeof styles == "string"){
4442 var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4444 while ((matches = re.exec(styles)) != null){
4445 el.setStyle(matches[1], matches[2]);
4447 }else if (typeof styles == "object"){
4448 for (var style in styles){
4449 el.setStyle(style, styles[style]);
4451 }else if (typeof styles == "function"){
4452 Roo.DomHelper.applyStyles(el, styles.call());
4458 * Inserts an HTML fragment into the Dom
4459 * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4460 * @param {HTMLElement} el The context element
4461 * @param {String} html The HTML fragmenet
4462 * @return {HTMLElement} The new node
4464 insertHtml : function(where, el, html){
4465 where = where.toLowerCase();
4466 if(el.insertAdjacentHTML){
4467 if(tableRe.test(el.tagName)){
4469 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4475 el.insertAdjacentHTML('BeforeBegin', html);
4476 return el.previousSibling;
4478 el.insertAdjacentHTML('AfterBegin', html);
4479 return el.firstChild;
4481 el.insertAdjacentHTML('BeforeEnd', html);
4482 return el.lastChild;
4484 el.insertAdjacentHTML('AfterEnd', html);
4485 return el.nextSibling;
4487 throw 'Illegal insertion point -> "' + where + '"';
4489 var range = el.ownerDocument.createRange();
4493 range.setStartBefore(el);
4494 frag = range.createContextualFragment(html);
4495 el.parentNode.insertBefore(frag, el);
4496 return el.previousSibling;
4499 range.setStartBefore(el.firstChild);
4500 frag = range.createContextualFragment(html);
4501 el.insertBefore(frag, el.firstChild);
4502 return el.firstChild;
4504 el.innerHTML = html;
4505 return el.firstChild;
4509 range.setStartAfter(el.lastChild);
4510 frag = range.createContextualFragment(html);
4511 el.appendChild(frag);
4512 return el.lastChild;
4514 el.innerHTML = html;
4515 return el.lastChild;
4518 range.setStartAfter(el);
4519 frag = range.createContextualFragment(html);
4520 el.parentNode.insertBefore(frag, el.nextSibling);
4521 return el.nextSibling;
4523 throw 'Illegal insertion point -> "' + where + '"';
4527 * Creates new Dom element(s) and inserts them before el
4528 * @param {String/HTMLElement/Element} el The context element
4529 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4530 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4531 * @return {HTMLElement/Roo.Element} The new node
4533 insertBefore : function(el, o, returnElement){
4534 return this.doInsert(el, o, returnElement, "beforeBegin");
4538 * Creates new Dom element(s) and inserts them after el
4539 * @param {String/HTMLElement/Element} el The context element
4540 * @param {Object} o The Dom object spec (and children)
4541 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4542 * @return {HTMLElement/Roo.Element} The new node
4544 insertAfter : function(el, o, returnElement){
4545 return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4549 * Creates new Dom element(s) and inserts them as the first child of el
4550 * @param {String/HTMLElement/Element} el The context element
4551 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4552 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4553 * @return {HTMLElement/Roo.Element} The new node
4555 insertFirst : function(el, o, returnElement){
4556 return this.doInsert(el, o, returnElement, "afterBegin");
4560 doInsert : function(el, o, returnElement, pos, sibling){
4561 el = Roo.getDom(el);
4563 if(this.useDom || o.ns){
4564 newNode = createDom(o, null);
4565 el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4567 var html = createHtml(o);
4568 newNode = this.insertHtml(pos, el, html);
4570 return returnElement ? Roo.get(newNode, true) : newNode;
4574 * Creates new Dom element(s) and appends them to el
4575 * @param {String/HTMLElement/Element} el The context element
4576 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4577 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4578 * @return {HTMLElement/Roo.Element} The new node
4580 append : function(el, o, returnElement){
4581 el = Roo.getDom(el);
4583 if(this.useDom || o.ns){
4584 newNode = createDom(o, null);
4585 el.appendChild(newNode);
4587 var html = createHtml(o);
4588 newNode = this.insertHtml("beforeEnd", el, html);
4590 return returnElement ? Roo.get(newNode, true) : newNode;
4594 * Creates new Dom element(s) and overwrites the contents of el with them
4595 * @param {String/HTMLElement/Element} el The context element
4596 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4597 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4598 * @return {HTMLElement/Roo.Element} The new node
4600 overwrite : function(el, o, returnElement){
4601 el = Roo.getDom(el);
4604 while (el.childNodes.length) {
4605 el.removeChild(el.firstChild);
4609 el.innerHTML = createHtml(o);
4612 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4616 * Creates a new Roo.DomHelper.Template from the Dom object spec
4617 * @param {Object} o The Dom object spec (and children)
4618 * @return {Roo.DomHelper.Template} The new template
4620 createTemplate : function(o){
4621 var html = createHtml(o);
4622 return new Roo.Template(html);
4628 * Ext JS Library 1.1.1
4629 * Copyright(c) 2006-2007, Ext JS, LLC.
4631 * Originally Released Under LGPL - original licence link has changed is not relivant.
4634 * <script type="text/javascript">
4638 * @class Roo.Template
4639 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4640 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4643 var t = new Roo.Template({
4644 html : '<div name="{id}">' +
4645 '<span class="{cls}">{name:trim} {someval:this.myformat}{value:ellipsis(10)}</span>' +
4647 myformat: function (value, allValues) {
4648 return 'XX' + value;
4651 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4653 * For more information see this blog post with examples:
4654 * <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4655 - Create Elements using DOM, HTML fragments and Templates</a>.
4657 * @param {Object} cfg - Configuration object.
4659 Roo.Template = function(cfg){
4661 if(cfg instanceof Array){
4663 }else if(arguments.length > 1){
4664 cfg = Array.prototype.join.call(arguments, "");
4668 if (typeof(cfg) == 'object') {
4679 Roo.Template.prototype = {
4682 * @cfg {Function} onLoad Called after the template has been loaded and complied (usually from a remove source)
4688 * @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..
4689 * it should be fixed so that template is observable...
4693 * @cfg {String} html The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4701 * Returns an HTML fragment of this template with the specified values applied.
4702 * @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'})
4703 * @return {String} The HTML fragment
4708 applyTemplate : function(values){
4709 //Roo.log(["applyTemplate", values]);
4713 return this.compiled(values);
4715 var useF = this.disableFormats !== true;
4716 var fm = Roo.util.Format, tpl = this;
4717 var fn = function(m, name, format, args){
4719 if(format.substr(0, 5) == "this."){
4720 return tpl.call(format.substr(5), values[name], values);
4723 // quoted values are required for strings in compiled templates,
4724 // but for non compiled we need to strip them
4725 // quoted reversed for jsmin
4726 var re = /^\s*['"](.*)["']\s*$/;
4727 args = args.split(',');
4728 for(var i = 0, len = args.length; i < len; i++){
4729 args[i] = args[i].replace(re, "$1");
4731 args = [values[name]].concat(args);
4733 args = [values[name]];
4735 return fm[format].apply(fm, args);
4738 return values[name] !== undefined ? values[name] : "";
4741 return this.html.replace(this.re, fn);
4759 this.loading = true;
4760 this.compiled = false;
4762 var cx = new Roo.data.Connection();
4766 success : function (response) {
4770 _t.set(response.responseText,true);
4776 failure : function(response) {
4777 Roo.log("Template failed to load from " + _t.url);
4784 * Sets the HTML used as the template and optionally compiles it.
4785 * @param {String} html
4786 * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4787 * @return {Roo.Template} this
4789 set : function(html, compile){
4791 this.compiled = false;
4799 * True to disable format functions (defaults to false)
4802 disableFormats : false,
4805 * The regular expression used to match template variables
4809 re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4812 * Compiles the template into an internal function, eliminating the RegEx overhead.
4813 * @return {Roo.Template} this
4815 compile : function(){
4816 var fm = Roo.util.Format;
4817 var useF = this.disableFormats !== true;
4818 var sep = Roo.isGecko ? "+" : ",";
4819 var fn = function(m, name, format, args){
4821 args = args ? ',' + args : "";
4822 if(format.substr(0, 5) != "this."){
4823 format = "fm." + format + '(';
4825 format = 'this.call("'+ format.substr(5) + '", ';
4829 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4831 return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4834 // branched to use + in gecko and [].join() in others
4836 body = "this.compiled = function(values){ return '" +
4837 this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4840 body = ["this.compiled = function(values){ return ['"];
4841 body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4842 body.push("'].join('');};");
4843 body = body.join('');
4853 // private function used to call members
4854 call : function(fnName, value, allValues){
4855 return this[fnName](value, allValues);
4859 * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4860 * @param {String/HTMLElement/Roo.Element} el The context element
4861 * @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'})
4862 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4863 * @return {HTMLElement/Roo.Element} The new node or Element
4865 insertFirst: function(el, values, returnElement){
4866 return this.doInsert('afterBegin', el, values, returnElement);
4870 * Applies the supplied values to the template and inserts the new node(s) before el.
4871 * @param {String/HTMLElement/Roo.Element} el The context element
4872 * @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'})
4873 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4874 * @return {HTMLElement/Roo.Element} The new node or Element
4876 insertBefore: function(el, values, returnElement){
4877 return this.doInsert('beforeBegin', el, values, returnElement);
4881 * Applies the supplied values to the template and inserts the new node(s) after el.
4882 * @param {String/HTMLElement/Roo.Element} el The context element
4883 * @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'})
4884 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4885 * @return {HTMLElement/Roo.Element} The new node or Element
4887 insertAfter : function(el, values, returnElement){
4888 return this.doInsert('afterEnd', el, values, returnElement);
4892 * Applies the supplied values to the template and appends the new node(s) to el.
4893 * @param {String/HTMLElement/Roo.Element} el The context element
4894 * @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'})
4895 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4896 * @return {HTMLElement/Roo.Element} The new node or Element
4898 append : function(el, values, returnElement){
4899 return this.doInsert('beforeEnd', el, values, returnElement);
4902 doInsert : function(where, el, values, returnEl){
4903 el = Roo.getDom(el);
4904 var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4905 return returnEl ? Roo.get(newNode, true) : newNode;
4909 * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4910 * @param {String/HTMLElement/Roo.Element} el The context element
4911 * @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'})
4912 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4913 * @return {HTMLElement/Roo.Element} The new node or Element
4915 overwrite : function(el, values, returnElement){
4916 el = Roo.getDom(el);
4917 el.innerHTML = this.applyTemplate(values);
4918 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4922 * Alias for {@link #applyTemplate}
4925 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4928 Roo.DomHelper.Template = Roo.Template;
4931 * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4932 * @param {String/HTMLElement} el A DOM element or its id
4933 * @returns {Roo.Template} The created template
4936 Roo.Template.from = function(el){
4937 el = Roo.getDom(el);
4938 return new Roo.Template(el.value || el.innerHTML);
4941 * Ext JS Library 1.1.1
4942 * Copyright(c) 2006-2007, Ext JS, LLC.
4944 * Originally Released Under LGPL - original licence link has changed is not relivant.
4947 * <script type="text/javascript">
4952 * This is code is also distributed under MIT license for use
4953 * with jQuery and prototype JavaScript libraries.
4956 * @class Roo.DomQuery
4957 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).
4959 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>
4962 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.
4964 <h4>Element Selectors:</h4>
4966 <li> <b>*</b> any element</li>
4967 <li> <b>E</b> an element with the tag E</li>
4968 <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4969 <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4970 <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4971 <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4973 <h4>Attribute Selectors:</h4>
4974 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4976 <li> <b>E[foo]</b> has an attribute "foo"</li>
4977 <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4978 <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4979 <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4980 <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4981 <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4982 <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4984 <h4>Pseudo Classes:</h4>
4986 <li> <b>E:first-child</b> E is the first child of its parent</li>
4987 <li> <b>E:last-child</b> E is the last child of its parent</li>
4988 <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>
4989 <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4990 <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4991 <li> <b>E:only-child</b> E is the only child of its parent</li>
4992 <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>
4993 <li> <b>E:first</b> the first E in the resultset</li>
4994 <li> <b>E:last</b> the last E in the resultset</li>
4995 <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4996 <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4997 <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4998 <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4999 <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
5000 <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
5001 <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
5002 <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
5003 <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
5005 <h4>CSS Value Selectors:</h4>
5007 <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
5008 <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
5009 <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
5010 <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
5011 <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
5012 <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
5016 Roo.DomQuery = function(){
5017 var cache = {}, simpleCache = {}, valueCache = {};
5018 var nonSpace = /\S/;
5019 var trimRe = /^\s+|\s+$/g;
5020 var tplRe = /\{(\d+)\}/g;
5021 var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
5022 var tagTokenRe = /^(#)?([\w-\*]+)/;
5023 var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
5025 function child(p, index){
5027 var n = p.firstChild;
5029 if(n.nodeType == 1){
5040 while((n = n.nextSibling) && n.nodeType != 1);
5045 while((n = n.previousSibling) && n.nodeType != 1);
5049 function children(d){
5050 var n = d.firstChild, ni = -1;
5052 var nx = n.nextSibling;
5053 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
5063 function byClassName(c, a, v){
5067 var r = [], ri = -1, cn;
5068 for(var i = 0, ci; ci = c[i]; i++){
5069 if((' '+ci.className+' ').indexOf(v) != -1){
5076 function attrValue(n, attr){
5077 if(!n.tagName && typeof n.length != "undefined"){
5086 if(attr == "class" || attr == "className"){
5089 return n.getAttribute(attr) || n[attr];
5093 function getNodes(ns, mode, tagName){
5094 var result = [], ri = -1, cs;
5098 tagName = tagName || "*";
5099 if(typeof ns.getElementsByTagName != "undefined"){
5103 for(var i = 0, ni; ni = ns[i]; i++){
5104 cs = ni.getElementsByTagName(tagName);
5105 for(var j = 0, ci; ci = cs[j]; j++){
5109 }else if(mode == "/" || mode == ">"){
5110 var utag = tagName.toUpperCase();
5111 for(var i = 0, ni, cn; ni = ns[i]; i++){
5112 cn = ni.children || ni.childNodes;
5113 for(var j = 0, cj; cj = cn[j]; j++){
5114 if(cj.nodeName == utag || cj.nodeName == tagName || tagName == '*'){
5119 }else if(mode == "+"){
5120 var utag = tagName.toUpperCase();
5121 for(var i = 0, n; n = ns[i]; i++){
5122 while((n = n.nextSibling) && n.nodeType != 1);
5123 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5127 }else if(mode == "~"){
5128 for(var i = 0, n; n = ns[i]; i++){
5129 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5138 function concat(a, b){
5142 for(var i = 0, l = b.length; i < l; i++){
5148 function byTag(cs, tagName){
5149 if(cs.tagName || cs == document){
5155 var r = [], ri = -1;
5156 tagName = tagName.toLowerCase();
5157 for(var i = 0, ci; ci = cs[i]; i++){
5158 if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5165 function byId(cs, attr, id){
5166 if(cs.tagName || cs == document){
5172 var r = [], ri = -1;
5173 for(var i = 0,ci; ci = cs[i]; i++){
5174 if(ci && ci.id == id){
5182 function byAttribute(cs, attr, value, op, custom){
5183 var r = [], ri = -1, st = custom=="{";
5184 var f = Roo.DomQuery.operators[op];
5185 for(var i = 0, ci; ci = cs[i]; i++){
5188 a = Roo.DomQuery.getStyle(ci, attr);
5190 else if(attr == "class" || attr == "className"){
5192 }else if(attr == "for"){
5194 }else if(attr == "href"){
5195 a = ci.getAttribute("href", 2);
5197 a = ci.getAttribute(attr);
5199 if((f && f(a, value)) || (!f && a)){
5206 function byPseudo(cs, name, value){
5207 return Roo.DomQuery.pseudos[name](cs, value);
5210 // This is for IE MSXML which does not support expandos.
5211 // IE runs the same speed using setAttribute, however FF slows way down
5212 // and Safari completely fails so they need to continue to use expandos.
5213 var isIE = window.ActiveXObject ? true : false;
5215 // this eval is stop the compressor from
5216 // renaming the variable to something shorter
5218 /** eval:var:batch */
5223 function nodupIEXml(cs){
5225 cs[0].setAttribute("_nodup", d);
5227 for(var i = 1, len = cs.length; i < len; i++){
5229 if(!c.getAttribute("_nodup") != d){
5230 c.setAttribute("_nodup", d);
5234 for(var i = 0, len = cs.length; i < len; i++){
5235 cs[i].removeAttribute("_nodup");
5244 var len = cs.length, c, i, r = cs, cj, ri = -1;
5245 if(!len || typeof cs.nodeType != "undefined" || len == 1){
5248 if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5249 return nodupIEXml(cs);
5253 for(i = 1; c = cs[i]; i++){
5258 for(var j = 0; j < i; j++){
5261 for(j = i+1; cj = cs[j]; j++){
5273 function quickDiffIEXml(c1, c2){
5275 for(var i = 0, len = c1.length; i < len; i++){
5276 c1[i].setAttribute("_qdiff", d);
5279 for(var i = 0, len = c2.length; i < len; i++){
5280 if(c2[i].getAttribute("_qdiff") != d){
5281 r[r.length] = c2[i];
5284 for(var i = 0, len = c1.length; i < len; i++){
5285 c1[i].removeAttribute("_qdiff");
5290 function quickDiff(c1, c2){
5291 var len1 = c1.length;
5295 if(isIE && c1[0].selectSingleNode){
5296 return quickDiffIEXml(c1, c2);
5299 for(var i = 0; i < len1; i++){
5303 for(var i = 0, len = c2.length; i < len; i++){
5304 if(c2[i]._qdiff != d){
5305 r[r.length] = c2[i];
5311 function quickId(ns, mode, root, id){
5313 var d = root.ownerDocument || root;
5314 return d.getElementById(id);
5316 ns = getNodes(ns, mode, "*");
5317 return byId(ns, null, id);
5321 getStyle : function(el, name){
5322 return Roo.fly(el).getStyle(name);
5325 * Compiles a selector/xpath query into a reusable function. The returned function
5326 * takes one parameter "root" (optional), which is the context node from where the query should start.
5327 * @param {String} selector The selector/xpath query
5328 * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5329 * @return {Function}
5331 compile : function(path, type){
5332 type = type || "select";
5334 var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5335 var q = path, mode, lq;
5336 var tk = Roo.DomQuery.matchers;
5337 var tklen = tk.length;
5340 // accept leading mode switch
5341 var lmode = q.match(modeRe);
5342 if(lmode && lmode[1]){
5343 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5344 q = q.replace(lmode[1], "");
5346 // strip leading slashes
5347 while(path.substr(0, 1)=="/"){
5348 path = path.substr(1);
5351 while(q && lq != q){
5353 var tm = q.match(tagTokenRe);
5354 if(type == "select"){
5357 fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5359 fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5361 q = q.replace(tm[0], "");
5362 }else if(q.substr(0, 1) != '@'){
5363 fn[fn.length] = 'n = getNodes(n, mode, "*");';
5368 fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5370 fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5372 q = q.replace(tm[0], "");
5375 while(!(mm = q.match(modeRe))){
5376 var matched = false;
5377 for(var j = 0; j < tklen; j++){
5379 var m = q.match(t.re);
5381 fn[fn.length] = t.select.replace(tplRe, function(x, i){
5384 q = q.replace(m[0], "");
5389 // prevent infinite loop on bad selector
5391 throw 'Error parsing selector, parsing failed at "' + q + '"';
5395 fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5396 q = q.replace(mm[1], "");
5399 fn[fn.length] = "return nodup(n);\n}";
5402 * list of variables that need from compression as they are used by eval.
5412 * eval:var:byClassName
5414 * eval:var:byAttribute
5415 * eval:var:attrValue
5423 * Selects a group of elements.
5424 * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5425 * @param {Node} root (optional) The start of the query (defaults to document).
5428 select : function(path, root, type){
5429 if(!root || root == document){
5432 if(typeof root == "string"){
5433 root = document.getElementById(root);
5435 var paths = path.split(",");
5437 for(var i = 0, len = paths.length; i < len; i++){
5438 var p = paths[i].replace(trimRe, "");
5440 cache[p] = Roo.DomQuery.compile(p);
5442 throw p + " is not a valid selector";
5445 var result = cache[p](root);
5446 if(result && result != document){
5447 results = results.concat(result);
5450 if(paths.length > 1){
5451 return nodup(results);
5457 * Selects a single element.
5458 * @param {String} selector The selector/xpath query
5459 * @param {Node} root (optional) The start of the query (defaults to document).
5462 selectNode : function(path, root){
5463 return Roo.DomQuery.select(path, root)[0];
5467 * Selects the value of a node, optionally replacing null with the defaultValue.
5468 * @param {String} selector The selector/xpath query
5469 * @param {Node} root (optional) The start of the query (defaults to document).
5470 * @param {String} defaultValue
5472 selectValue : function(path, root, defaultValue){
5473 path = path.replace(trimRe, "");
5474 if(!valueCache[path]){
5475 valueCache[path] = Roo.DomQuery.compile(path, "select");
5477 var n = valueCache[path](root);
5478 n = n[0] ? n[0] : n;
5479 var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5480 return ((v === null||v === undefined||v==='') ? defaultValue : v);
5484 * Selects the value of a node, parsing integers and floats.
5485 * @param {String} selector The selector/xpath query
5486 * @param {Node} root (optional) The start of the query (defaults to document).
5487 * @param {Number} defaultValue
5490 selectNumber : function(path, root, defaultValue){
5491 var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5492 return parseFloat(v);
5496 * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5497 * @param {String/HTMLElement/Array} el An element id, element or array of elements
5498 * @param {String} selector The simple selector to test
5501 is : function(el, ss){
5502 if(typeof el == "string"){
5503 el = document.getElementById(el);
5505 var isArray = (el instanceof Array);
5506 var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5507 return isArray ? (result.length == el.length) : (result.length > 0);
5511 * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5512 * @param {Array} el An array of elements to filter
5513 * @param {String} selector The simple selector to test
5514 * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5515 * the selector instead of the ones that match
5518 filter : function(els, ss, nonMatches){
5519 ss = ss.replace(trimRe, "");
5520 if(!simpleCache[ss]){
5521 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5523 var result = simpleCache[ss](els);
5524 return nonMatches ? quickDiff(result, els) : result;
5528 * Collection of matching regular expressions and code snippets.
5532 select: 'n = byClassName(n, null, " {1} ");'
5534 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5535 select: 'n = byPseudo(n, "{1}", "{2}");'
5537 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5538 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5541 select: 'n = byId(n, null, "{1}");'
5544 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5549 * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5550 * 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, > <.
5553 "=" : function(a, v){
5556 "!=" : function(a, v){
5559 "^=" : function(a, v){
5560 return a && a.substr(0, v.length) == v;
5562 "$=" : function(a, v){
5563 return a && a.substr(a.length-v.length) == v;
5565 "*=" : function(a, v){
5566 return a && a.indexOf(v) !== -1;
5568 "%=" : function(a, v){
5569 return (a % v) == 0;
5571 "|=" : function(a, v){
5572 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5574 "~=" : function(a, v){
5575 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5580 * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5581 * and the argument (if any) supplied in the selector.
5584 "first-child" : function(c){
5585 var r = [], ri = -1, n;
5586 for(var i = 0, ci; ci = n = c[i]; i++){
5587 while((n = n.previousSibling) && n.nodeType != 1);
5595 "last-child" : function(c){
5596 var r = [], ri = -1, n;
5597 for(var i = 0, ci; ci = n = c[i]; i++){
5598 while((n = n.nextSibling) && n.nodeType != 1);
5606 "nth-child" : function(c, a) {
5607 var r = [], ri = -1;
5608 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5609 var f = (m[1] || 1) - 0, l = m[2] - 0;
5610 for(var i = 0, n; n = c[i]; i++){
5611 var pn = n.parentNode;
5612 if (batch != pn._batch) {
5614 for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5615 if(cn.nodeType == 1){
5622 if (l == 0 || n.nodeIndex == l){
5625 } else if ((n.nodeIndex + l) % f == 0){
5633 "only-child" : function(c){
5634 var r = [], ri = -1;;
5635 for(var i = 0, ci; ci = c[i]; i++){
5636 if(!prev(ci) && !next(ci)){
5643 "empty" : function(c){
5644 var r = [], ri = -1;
5645 for(var i = 0, ci; ci = c[i]; i++){
5646 var cns = ci.childNodes, j = 0, cn, empty = true;
5649 if(cn.nodeType == 1 || cn.nodeType == 3){
5661 "contains" : function(c, v){
5662 var r = [], ri = -1;
5663 for(var i = 0, ci; ci = c[i]; i++){
5664 if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5671 "nodeValue" : function(c, v){
5672 var r = [], ri = -1;
5673 for(var i = 0, ci; ci = c[i]; i++){
5674 if(ci.firstChild && ci.firstChild.nodeValue == v){
5681 "checked" : function(c){
5682 var r = [], ri = -1;
5683 for(var i = 0, ci; ci = c[i]; i++){
5684 if(ci.checked == true){
5691 "not" : function(c, ss){
5692 return Roo.DomQuery.filter(c, ss, true);
5695 "odd" : function(c){
5696 return this["nth-child"](c, "odd");
5699 "even" : function(c){
5700 return this["nth-child"](c, "even");
5703 "nth" : function(c, a){
5704 return c[a-1] || [];
5707 "first" : function(c){
5711 "last" : function(c){
5712 return c[c.length-1] || [];
5715 "has" : function(c, ss){
5716 var s = Roo.DomQuery.select;
5717 var r = [], ri = -1;
5718 for(var i = 0, ci; ci = c[i]; i++){
5719 if(s(ss, ci).length > 0){
5726 "next" : function(c, ss){
5727 var is = Roo.DomQuery.is;
5728 var r = [], ri = -1;
5729 for(var i = 0, ci; ci = c[i]; i++){
5738 "prev" : function(c, ss){
5739 var is = Roo.DomQuery.is;
5740 var r = [], ri = -1;
5741 for(var i = 0, ci; ci = c[i]; i++){
5754 * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5755 * @param {String} path The selector/xpath query
5756 * @param {Node} root (optional) The start of the query (defaults to document).
5761 Roo.query = Roo.DomQuery.select;
5764 * Ext JS Library 1.1.1
5765 * Copyright(c) 2006-2007, Ext JS, LLC.
5767 * Originally Released Under LGPL - original licence link has changed is not relivant.
5770 * <script type="text/javascript">
5774 * @class Roo.util.Observable
5775 * Base class that provides a common interface for publishing events. Subclasses are expected to
5776 * to have a property "events" with all the events defined.<br>
5779 Employee = function(name){
5786 Roo.extend(Employee, Roo.util.Observable);
5788 * @param {Object} config properties to use (incuding events / listeners)
5791 Roo.util.Observable = function(cfg){
5794 this.addEvents(cfg.events || {});
5796 delete cfg.events; // make sure
5799 Roo.apply(this, cfg);
5802 this.on(this.listeners);
5803 delete this.listeners;
5806 Roo.util.Observable.prototype = {
5808 * @cfg {Object} listeners list of events and functions to call for this object,
5812 'click' : function(e) {
5822 * Fires the specified event with the passed parameters (minus the event name).
5823 * @param {String} eventName
5824 * @param {Object...} args Variable number of parameters are passed to handlers
5825 * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5827 fireEvent : function(){
5828 var ce = this.events[arguments[0].toLowerCase()];
5829 if(typeof ce == "object"){
5830 return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5837 filterOptRe : /^(?:scope|delay|buffer|single)$/,
5840 * Appends an event handler to this component
5841 * @param {String} eventName The type of event to listen for
5842 * @param {Function} handler The method the event invokes
5843 * @param {Object} scope (optional) The scope in which to execute the handler
5844 * function. The handler function's "this" context.
5845 * @param {Object} options (optional) An object containing handler configuration
5846 * properties. This may contain any of the following properties:<ul>
5847 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5848 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5849 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5850 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5851 * by the specified number of milliseconds. If the event fires again within that time, the original
5852 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5855 * <b>Combining Options</b><br>
5856 * Using the options argument, it is possible to combine different types of listeners:<br>
5858 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5860 el.on('click', this.onClick, this, {
5867 * <b>Attaching multiple handlers in 1 call</b><br>
5868 * The method also allows for a single argument to be passed which is a config object containing properties
5869 * which specify multiple handlers.
5878 fn: this.onMouseOver,
5882 fn: this.onMouseOut,
5888 * Or a shorthand syntax which passes the same scope object to all handlers:
5891 'click': this.onClick,
5892 'mouseover': this.onMouseOver,
5893 'mouseout': this.onMouseOut,
5898 addListener : function(eventName, fn, scope, o){
5899 if(typeof eventName == "object"){
5902 if(this.filterOptRe.test(e)){
5905 if(typeof o[e] == "function"){
5907 this.addListener(e, o[e], o.scope, o);
5909 // individual options
5910 this.addListener(e, o[e].fn, o[e].scope, o[e]);
5915 o = (!o || typeof o == "boolean") ? {} : o;
5916 eventName = eventName.toLowerCase();
5917 var ce = this.events[eventName] || true;
5918 if(typeof ce == "boolean"){
5919 ce = new Roo.util.Event(this, eventName);
5920 this.events[eventName] = ce;
5922 ce.addListener(fn, scope, o);
5926 * Removes a listener
5927 * @param {String} eventName The type of event to listen for
5928 * @param {Function} handler The handler to remove
5929 * @param {Object} scope (optional) The scope (this object) for the handler
5931 removeListener : function(eventName, fn, scope){
5932 var ce = this.events[eventName.toLowerCase()];
5933 if(typeof ce == "object"){
5934 ce.removeListener(fn, scope);
5939 * Removes all listeners for this object
5941 purgeListeners : function(){
5942 for(var evt in this.events){
5943 if(typeof this.events[evt] == "object"){
5944 this.events[evt].clearListeners();
5949 relayEvents : function(o, events){
5950 var createHandler = function(ename){
5953 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5956 for(var i = 0, len = events.length; i < len; i++){
5957 var ename = events[i];
5958 if(!this.events[ename]){
5959 this.events[ename] = true;
5961 o.on(ename, createHandler(ename), this);
5966 * Used to define events on this Observable
5967 * @param {Object} object The object with the events defined
5969 addEvents : function(o){
5973 Roo.applyIf(this.events, o);
5977 * Checks to see if this object has any listeners for a specified event
5978 * @param {String} eventName The name of the event to check for
5979 * @return {Boolean} True if the event is being listened for, else false
5981 hasListener : function(eventName){
5982 var e = this.events[eventName];
5983 return typeof e == "object" && e.listeners.length > 0;
5987 * Appends an event handler to this element (shorthand for addListener)
5988 * @param {String} eventName The type of event to listen for
5989 * @param {Function} handler The method the event invokes
5990 * @param {Object} scope (optional) The scope in which to execute the handler
5991 * function. The handler function's "this" context.
5992 * @param {Object} options (optional)
5995 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5997 * Removes a listener (shorthand for removeListener)
5998 * @param {String} eventName The type of event to listen for
5999 * @param {Function} handler The handler to remove
6000 * @param {Object} scope (optional) The scope (this object) for the handler
6003 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
6006 * Starts capture on the specified Observable. All events will be passed
6007 * to the supplied function with the event name + standard signature of the event
6008 * <b>before</b> the event is fired. If the supplied function returns false,
6009 * the event will not fire.
6010 * @param {Observable} o The Observable to capture
6011 * @param {Function} fn The function to call
6012 * @param {Object} scope (optional) The scope (this object) for the fn
6015 Roo.util.Observable.capture = function(o, fn, scope){
6016 o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
6020 * Removes <b>all</b> added captures from the Observable.
6021 * @param {Observable} o The Observable to release
6024 Roo.util.Observable.releaseCapture = function(o){
6025 o.fireEvent = Roo.util.Observable.prototype.fireEvent;
6030 var createBuffered = function(h, o, scope){
6031 var task = new Roo.util.DelayedTask();
6033 task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
6037 var createSingle = function(h, e, fn, scope){
6039 e.removeListener(fn, scope);
6040 return h.apply(scope, arguments);
6044 var createDelayed = function(h, o, scope){
6046 var args = Array.prototype.slice.call(arguments, 0);
6047 setTimeout(function(){
6048 h.apply(scope, args);
6053 Roo.util.Event = function(obj, name){
6056 this.listeners = [];
6059 Roo.util.Event.prototype = {
6060 addListener : function(fn, scope, options){
6061 var o = options || {};
6062 scope = scope || this.obj;
6063 if(!this.isListening(fn, scope)){
6064 var l = {fn: fn, scope: scope, options: o};
6067 h = createDelayed(h, o, scope);
6070 h = createSingle(h, this, fn, scope);
6073 h = createBuffered(h, o, scope);
6076 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
6077 this.listeners.push(l);
6079 this.listeners = this.listeners.slice(0);
6080 this.listeners.push(l);
6085 findListener : function(fn, scope){
6086 scope = scope || this.obj;
6087 var ls = this.listeners;
6088 for(var i = 0, len = ls.length; i < len; i++){
6090 if(l.fn == fn && l.scope == scope){
6097 isListening : function(fn, scope){
6098 return this.findListener(fn, scope) != -1;
6101 removeListener : function(fn, scope){
6103 if((index = this.findListener(fn, scope)) != -1){
6105 this.listeners.splice(index, 1);
6107 this.listeners = this.listeners.slice(0);
6108 this.listeners.splice(index, 1);
6115 clearListeners : function(){
6116 this.listeners = [];
6120 var ls = this.listeners, scope, len = ls.length;
6123 var args = Array.prototype.slice.call(arguments, 0);
6124 for(var i = 0; i < len; i++){
6126 if(l.fireFn.apply(l.scope||this.obj||window, args) === false){
6127 this.firing = false;
6131 this.firing = false;
6138 * Copyright(c) 2007-2017, Roo J Solutions Ltd
6145 * @class Roo.Document
6146 * @extends Roo.util.Observable
6147 * This is a convience class to wrap up the main document loading code.. , rather than adding Roo.onReady(......)
6149 * @param {Object} config the methods and properties of the 'base' class for the application.
6151 * Generic Page handler - implement this to start your app..
6154 * MyProject = new Roo.Document({
6156 'load' : true // your events..
6159 'ready' : function() {
6160 // fired on Roo.onReady()
6165 Roo.Document = function(cfg) {
6170 Roo.util.Observable.call(this,cfg);
6174 Roo.onReady(function() {
6175 _this.fireEvent('ready');
6181 Roo.extend(Roo.Document, Roo.util.Observable, {});/*
6183 * Ext JS Library 1.1.1
6184 * Copyright(c) 2006-2007, Ext JS, LLC.
6186 * Originally Released Under LGPL - original licence link has changed is not relivant.
6189 * <script type="text/javascript">
6193 * @class Roo.EventManager
6194 * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
6195 * several useful events directly.
6196 * See {@link Roo.EventObject} for more details on normalized event objects.
6199 Roo.EventManager = function(){
6200 var docReadyEvent, docReadyProcId, docReadyState = false;
6201 var resizeEvent, resizeTask, textEvent, textSize;
6202 var E = Roo.lib.Event;
6203 var D = Roo.lib.Dom;
6208 var fireDocReady = function(){
6210 docReadyState = true;
6213 clearInterval(docReadyProcId);
6215 if(Roo.isGecko || Roo.isOpera) {
6216 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6219 var defer = document.getElementById("ie-deferred-loader");
6221 defer.onreadystatechange = null;
6222 defer.parentNode.removeChild(defer);
6226 docReadyEvent.fire();
6227 docReadyEvent.clearListeners();
6232 var initDocReady = function(){
6233 docReadyEvent = new Roo.util.Event();
6234 if(Roo.isGecko || Roo.isOpera) {
6235 document.addEventListener("DOMContentLoaded", fireDocReady, false);
6237 document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6238 var defer = document.getElementById("ie-deferred-loader");
6239 defer.onreadystatechange = function(){
6240 if(this.readyState == "complete"){
6244 }else if(Roo.isSafari){
6245 docReadyProcId = setInterval(function(){
6246 var rs = document.readyState;
6247 if(rs == "complete") {
6252 // no matter what, make sure it fires on load
6253 E.on(window, "load", fireDocReady);
6256 var createBuffered = function(h, o){
6257 var task = new Roo.util.DelayedTask(h);
6259 // create new event object impl so new events don't wipe out properties
6260 e = new Roo.EventObjectImpl(e);
6261 task.delay(o.buffer, h, null, [e]);
6265 var createSingle = function(h, el, ename, fn){
6267 Roo.EventManager.removeListener(el, ename, fn);
6272 var createDelayed = function(h, o){
6274 // create new event object impl so new events don't wipe out properties
6275 e = new Roo.EventObjectImpl(e);
6276 setTimeout(function(){
6281 var transitionEndVal = false;
6283 var transitionEnd = function()
6285 if (transitionEndVal) {
6286 return transitionEndVal;
6288 var el = document.createElement('div');
6290 var transEndEventNames = {
6291 WebkitTransition : 'webkitTransitionEnd',
6292 MozTransition : 'transitionend',
6293 OTransition : 'oTransitionEnd otransitionend',
6294 transition : 'transitionend'
6297 for (var name in transEndEventNames) {
6298 if (el.style[name] !== undefined) {
6299 transitionEndVal = transEndEventNames[name];
6300 return transitionEndVal ;
6307 var listen = function(element, ename, opt, fn, scope)
6309 var o = (!opt || typeof opt == "boolean") ? {} : opt;
6310 fn = fn || o.fn; scope = scope || o.scope;
6311 var el = Roo.getDom(element);
6315 throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6318 if (ename == 'transitionend') {
6319 ename = transitionEnd();
6321 var h = function(e){
6322 e = Roo.EventObject.setEvent(e);
6325 t = e.getTarget(o.delegate, el);
6332 if(o.stopEvent === true){
6335 if(o.preventDefault === true){
6338 if(o.stopPropagation === true){
6339 e.stopPropagation();
6342 if(o.normalized === false){
6346 fn.call(scope || el, e, t, o);
6349 h = createDelayed(h, o);
6352 h = createSingle(h, el, ename, fn);
6355 h = createBuffered(h, o);
6358 fn._handlers = fn._handlers || [];
6361 fn._handlers.push([Roo.id(el), ename, h]);
6365 E.on(el, ename, h); // this adds the actuall listener to the object..
6368 if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6369 el.addEventListener("DOMMouseScroll", h, false);
6370 E.on(window, 'unload', function(){
6371 el.removeEventListener("DOMMouseScroll", h, false);
6374 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6375 Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6380 var stopListening = function(el, ename, fn){
6381 var id = Roo.id(el), hds = fn._handlers, hd = fn;
6383 for(var i = 0, len = hds.length; i < len; i++){
6385 if(h[0] == id && h[1] == ename){
6392 E.un(el, ename, hd);
6393 el = Roo.getDom(el);
6394 if(ename == "mousewheel" && el.addEventListener){
6395 el.removeEventListener("DOMMouseScroll", hd, false);
6397 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6398 Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6402 var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6409 * @scope Roo.EventManager
6414 * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6415 * object with a Roo.EventObject
6416 * @param {Function} fn The method the event invokes
6417 * @param {Object} scope An object that becomes the scope of the handler
6418 * @param {boolean} override If true, the obj passed in becomes
6419 * the execution scope of the listener
6420 * @return {Function} The wrapped function
6423 wrap : function(fn, scope, override){
6425 Roo.EventObject.setEvent(e);
6426 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6431 * Appends an event handler to an element (shorthand for addListener)
6432 * @param {String/HTMLElement} element The html element or id to assign the
6433 * @param {String} eventName The type of event to listen for
6434 * @param {Function} handler The method the event invokes
6435 * @param {Object} scope (optional) The scope in which to execute the handler
6436 * function. The handler function's "this" context.
6437 * @param {Object} options (optional) An object containing handler configuration
6438 * properties. This may contain any of the following properties:<ul>
6439 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6440 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6441 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6442 * <li>preventDefault {Boolean} True to prevent the default action</li>
6443 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6444 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6445 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6446 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6447 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6448 * by the specified number of milliseconds. If the event fires again within that time, the original
6449 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6452 * <b>Combining Options</b><br>
6453 * Using the options argument, it is possible to combine different types of listeners:<br>
6455 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6457 el.on('click', this.onClick, this, {
6464 * <b>Attaching multiple handlers in 1 call</b><br>
6465 * The method also allows for a single argument to be passed which is a config object containing properties
6466 * which specify multiple handlers.
6476 fn: this.onMouseOver
6485 * Or a shorthand syntax:<br>
6488 'click' : this.onClick,
6489 'mouseover' : this.onMouseOver,
6490 'mouseout' : this.onMouseOut
6494 addListener : function(element, eventName, fn, scope, options){
6495 if(typeof eventName == "object"){
6501 if(typeof o[e] == "function"){
6503 listen(element, e, o, o[e], o.scope);
6505 // individual options
6506 listen(element, e, o[e]);
6511 return listen(element, eventName, options, fn, scope);
6515 * Removes an event handler
6517 * @param {String/HTMLElement} element The id or html element to remove the
6519 * @param {String} eventName The type of event
6520 * @param {Function} fn
6521 * @return {Boolean} True if a listener was actually removed
6523 removeListener : function(element, eventName, fn){
6524 return stopListening(element, eventName, fn);
6528 * Fires when the document is ready (before onload and before images are loaded). Can be
6529 * accessed shorthanded Roo.onReady().
6530 * @param {Function} fn The method the event invokes
6531 * @param {Object} scope An object that becomes the scope of the handler
6532 * @param {boolean} options
6534 onDocumentReady : function(fn, scope, options){
6535 if(docReadyState){ // if it already fired
6536 docReadyEvent.addListener(fn, scope, options);
6537 docReadyEvent.fire();
6538 docReadyEvent.clearListeners();
6544 docReadyEvent.addListener(fn, scope, options);
6548 * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6549 * @param {Function} fn The method the event invokes
6550 * @param {Object} scope An object that becomes the scope of the handler
6551 * @param {boolean} options
6553 onWindowResize : function(fn, scope, options){
6555 resizeEvent = new Roo.util.Event();
6556 resizeTask = new Roo.util.DelayedTask(function(){
6557 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6559 E.on(window, "resize", function(){
6561 resizeTask.delay(50);
6563 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6567 resizeEvent.addListener(fn, scope, options);
6571 * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6572 * @param {Function} fn The method the event invokes
6573 * @param {Object} scope An object that becomes the scope of the handler
6574 * @param {boolean} options
6576 onTextResize : function(fn, scope, options){
6578 textEvent = new Roo.util.Event();
6579 var textEl = new Roo.Element(document.createElement('div'));
6580 textEl.dom.className = 'x-text-resize';
6581 textEl.dom.innerHTML = 'X';
6582 textEl.appendTo(document.body);
6583 textSize = textEl.dom.offsetHeight;
6584 setInterval(function(){
6585 if(textEl.dom.offsetHeight != textSize){
6586 textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6588 }, this.textResizeInterval);
6590 textEvent.addListener(fn, scope, options);
6594 * Removes the passed window resize listener.
6595 * @param {Function} fn The method the event invokes
6596 * @param {Object} scope The scope of handler
6598 removeResizeListener : function(fn, scope){
6600 resizeEvent.removeListener(fn, scope);
6605 fireResize : function(){
6607 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6611 * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6615 * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6617 textResizeInterval : 50
6622 * @scopeAlias pub=Roo.EventManager
6626 * Appends an event handler to an element (shorthand for addListener)
6627 * @param {String/HTMLElement} element The html element or id to assign the
6628 * @param {String} eventName The type of event to listen for
6629 * @param {Function} handler The method the event invokes
6630 * @param {Object} scope (optional) The scope in which to execute the handler
6631 * function. The handler function's "this" context.
6632 * @param {Object} options (optional) An object containing handler configuration
6633 * properties. This may contain any of the following properties:<ul>
6634 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6635 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6636 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6637 * <li>preventDefault {Boolean} True to prevent the default action</li>
6638 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6639 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6640 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6641 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6642 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6643 * by the specified number of milliseconds. If the event fires again within that time, the original
6644 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6647 * <b>Combining Options</b><br>
6648 * Using the options argument, it is possible to combine different types of listeners:<br>
6650 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6652 el.on('click', this.onClick, this, {
6659 * <b>Attaching multiple handlers in 1 call</b><br>
6660 * The method also allows for a single argument to be passed which is a config object containing properties
6661 * which specify multiple handlers.
6671 fn: this.onMouseOver
6680 * Or a shorthand syntax:<br>
6683 'click' : this.onClick,
6684 'mouseover' : this.onMouseOver,
6685 'mouseout' : this.onMouseOut
6689 pub.on = pub.addListener;
6690 pub.un = pub.removeListener;
6692 pub.stoppedMouseDownEvent = new Roo.util.Event();
6696 * Fires when the document is ready (before onload and before images are loaded). Shorthand of {@link Roo.EventManager#onDocumentReady}.
6697 * @param {Function} fn The method the event invokes
6698 * @param {Object} scope An object that becomes the scope of the handler
6699 * @param {boolean} override If true, the obj passed in becomes
6700 * the execution scope of the listener
6704 Roo.onReady = Roo.EventManager.onDocumentReady;
6706 Roo.onReady(function(){
6707 var bd = Roo.get(document.body);
6712 : Roo.isIE11 ? "roo-ie11"
6713 : Roo.isEdge ? "roo-edge"
6714 : Roo.isGecko ? "roo-gecko"
6715 : Roo.isOpera ? "roo-opera"
6716 : Roo.isSafari ? "roo-safari" : ""];
6719 cls.push("roo-mac");
6722 cls.push("roo-linux");
6725 cls.push("roo-ios");
6728 cls.push("roo-touch");
6730 if(Roo.isBorderBox){
6731 cls.push('roo-border-box');
6733 if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6734 var p = bd.dom.parentNode;
6736 p.className += ' roo-strict';
6739 bd.addClass(cls.join(' '));
6743 * @class Roo.EventObject
6744 * EventObject exposes the Yahoo! UI Event functionality directly on the object
6745 * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code
6748 function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6750 var target = e.getTarget();
6753 var myDiv = Roo.get("myDiv");
6754 myDiv.on("click", handleClick);
6756 Roo.EventManager.on("myDiv", 'click', handleClick);
6757 Roo.EventManager.addListener("myDiv", 'click', handleClick);
6761 Roo.EventObject = function(){
6763 var E = Roo.lib.Event;
6765 // safari keypress events for special keys return bad keycodes
6768 63235 : 39, // right
6771 63276 : 33, // page up
6772 63277 : 34, // page down
6773 63272 : 46, // delete
6778 // normalize button clicks
6779 var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6780 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6782 Roo.EventObjectImpl = function(e){
6784 this.setEvent(e.browserEvent || e);
6787 Roo.EventObjectImpl.prototype = {
6789 * Used to fix doc tools.
6790 * @scope Roo.EventObject.prototype
6796 /** The normal browser event */
6797 browserEvent : null,
6798 /** The button pressed in a mouse event */
6800 /** True if the shift key was down during the event */
6802 /** True if the control key was down during the event */
6804 /** True if the alt key was down during the event */
6863 setEvent : function(e){
6864 if(e == this || (e && e.browserEvent)){ // already wrapped
6867 this.browserEvent = e;
6869 // normalize buttons
6870 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6871 if(e.type == 'click' && this.button == -1){
6875 this.shiftKey = e.shiftKey;
6876 // mac metaKey behaves like ctrlKey
6877 this.ctrlKey = e.ctrlKey || e.metaKey;
6878 this.altKey = e.altKey;
6879 // in getKey these will be normalized for the mac
6880 this.keyCode = e.keyCode;
6881 // keyup warnings on firefox.
6882 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6883 // cache the target for the delayed and or buffered events
6884 this.target = E.getTarget(e);
6886 this.xy = E.getXY(e);
6889 this.shiftKey = false;
6890 this.ctrlKey = false;
6891 this.altKey = false;
6901 * Stop the event (preventDefault and stopPropagation)
6903 stopEvent : function(){
6904 if(this.browserEvent){
6905 if(this.browserEvent.type == 'mousedown'){
6906 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6908 E.stopEvent(this.browserEvent);
6913 * Prevents the browsers default handling of the event.
6915 preventDefault : function(){
6916 if(this.browserEvent){
6917 E.preventDefault(this.browserEvent);
6922 isNavKeyPress : function(){
6923 var k = this.keyCode;
6924 k = Roo.isSafari ? (safariKeys[k] || k) : k;
6925 return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6928 isSpecialKey : function(){
6929 var k = this.keyCode;
6930 return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13 || k == 40 || k == 27 ||
6931 (k == 16) || (k == 17) ||
6932 (k >= 18 && k <= 20) ||
6933 (k >= 33 && k <= 35) ||
6934 (k >= 36 && k <= 39) ||
6935 (k >= 44 && k <= 45);
6938 * Cancels bubbling of the event.
6940 stopPropagation : function(){
6941 if(this.browserEvent){
6942 if(this.type == 'mousedown'){
6943 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6945 E.stopPropagation(this.browserEvent);
6950 * Gets the key code for the event.
6953 getCharCode : function(){
6954 return this.charCode || this.keyCode;
6958 * Returns a normalized keyCode for the event.
6959 * @return {Number} The key code
6961 getKey : function(){
6962 var k = this.keyCode || this.charCode;
6963 return Roo.isSafari ? (safariKeys[k] || k) : k;
6967 * Gets the x coordinate of the event.
6970 getPageX : function(){
6975 * Gets the y coordinate of the event.
6978 getPageY : function(){
6983 * Gets the time of the event.
6986 getTime : function(){
6987 if(this.browserEvent){
6988 return E.getTime(this.browserEvent);
6994 * Gets the page coordinates of the event.
6995 * @return {Array} The xy values like [x, y]
7002 * Gets the target for the event.
7003 * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
7004 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7005 search as a number or element (defaults to 10 || document.body)
7006 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7007 * @return {HTMLelement}
7009 getTarget : function(selector, maxDepth, returnEl){
7010 return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
7013 * Gets the related target.
7014 * @return {HTMLElement}
7016 getRelatedTarget : function(){
7017 if(this.browserEvent){
7018 return E.getRelatedTarget(this.browserEvent);
7024 * Normalizes mouse wheel delta across browsers
7025 * @return {Number} The delta
7027 getWheelDelta : function(){
7028 var e = this.browserEvent;
7030 if(e.wheelDelta){ /* IE/Opera. */
7031 delta = e.wheelDelta/120;
7032 }else if(e.detail){ /* Mozilla case. */
7033 delta = -e.detail/3;
7039 * Returns true if the control, meta, shift or alt key was pressed during this event.
7042 hasModifier : function(){
7043 return !!((this.ctrlKey || this.altKey) || this.shiftKey);
7047 * Returns true if the target of this event equals el or is a child of el
7048 * @param {String/HTMLElement/Element} el
7049 * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
7052 within : function(el, related){
7053 var t = this[related ? "getRelatedTarget" : "getTarget"]();
7054 return t && Roo.fly(el).contains(t);
7057 getPoint : function(){
7058 return new Roo.lib.Point(this.xy[0], this.xy[1]);
7062 return new Roo.EventObjectImpl();
7067 * Ext JS Library 1.1.1
7068 * Copyright(c) 2006-2007, Ext JS, LLC.
7070 * Originally Released Under LGPL - original licence link has changed is not relivant.
7073 * <script type="text/javascript">
7077 // was in Composite Element!??!?!
7080 var D = Roo.lib.Dom;
7081 var E = Roo.lib.Event;
7082 var A = Roo.lib.Anim;
7084 // local style camelizing for speed
7086 var camelRe = /(-[a-z])/gi;
7087 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
7088 var view = document.defaultView;
7091 * @class Roo.Element
7092 * Represents an Element in the DOM.<br><br>
7095 var el = Roo.get("my-div");
7098 var el = getEl("my-div");
7100 // or with a DOM element
7101 var el = Roo.get(myDivElement);
7103 * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
7104 * each call instead of constructing a new one.<br><br>
7105 * <b>Animations</b><br />
7106 * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
7107 * should either be a boolean (true) or an object literal with animation options. The animation options are:
7109 Option Default Description
7110 --------- -------- ---------------------------------------------
7111 duration .35 The duration of the animation in seconds
7112 easing easeOut The YUI easing method
7113 callback none A function to execute when the anim completes
7114 scope this The scope (this) of the callback function
7116 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
7117 * manipulate the animation. Here's an example:
7119 var el = Roo.get("my-div");
7124 // default animation
7125 el.setWidth(100, true);
7127 // animation with some options set
7134 // using the "anim" property to get the Anim object
7140 el.setWidth(100, opt);
7142 if(opt.anim.isAnimated()){
7146 * <b> Composite (Collections of) Elements</b><br />
7147 * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
7148 * @constructor Create a new Element directly.
7149 * @param {String/HTMLElement} element
7150 * @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).
7152 Roo.Element = function(element, forceNew)
7154 var dom = typeof element == "string" ?
7155 document.getElementById(element) : element;
7157 this.listeners = {};
7159 if(!dom){ // invalid id/element
7163 if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
7164 return Roo.Element.cache[id];
7174 * The DOM element ID
7177 this.id = id || Roo.id(dom);
7179 return this; // assumed for cctor?
7182 var El = Roo.Element;
7186 * The element's default display mode (defaults to "")
7189 originalDisplay : "",
7192 // note this is overridden in BS version..
7195 * The default unit to append to CSS values where a unit isn't provided (defaults to px).
7201 * Sets the element's visibility mode. When setVisible() is called it
7202 * will use this to determine whether to set the visibility or the display property.
7203 * @param visMode Element.VISIBILITY or Element.DISPLAY
7204 * @return {Roo.Element} this
7206 setVisibilityMode : function(visMode){
7207 this.visibilityMode = visMode;
7211 * Convenience method for setVisibilityMode(Element.DISPLAY)
7212 * @param {String} display (optional) What to set display to when visible
7213 * @return {Roo.Element} this
7215 enableDisplayMode : function(display){
7216 this.setVisibilityMode(El.DISPLAY);
7217 if(typeof display != "undefined") { this.originalDisplay = display; }
7222 * 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)
7223 * @param {String} selector The simple selector to test
7224 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7225 search as a number or element (defaults to 10 || document.body)
7226 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7227 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7229 findParent : function(simpleSelector, maxDepth, returnEl){
7230 var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7231 maxDepth = maxDepth || 50;
7232 if(typeof maxDepth != "number"){
7233 stopEl = Roo.getDom(maxDepth);
7236 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7237 if(dq.is(p, simpleSelector)){
7238 return returnEl ? Roo.get(p) : p;
7248 * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7249 * @param {String} selector The simple selector to test
7250 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7251 search as a number or element (defaults to 10 || document.body)
7252 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7253 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7255 findParentNode : function(simpleSelector, maxDepth, returnEl){
7256 var p = Roo.fly(this.dom.parentNode, '_internal');
7257 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7261 * Looks at the scrollable parent element
7263 findScrollableParent : function()
7265 var overflowRegex = /(auto|scroll)/;
7267 if(this.getStyle('position') === 'fixed'){
7268 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7271 var excludeStaticParent = this.getStyle('position') === "absolute";
7273 for (var parent = this; (parent = Roo.get(parent.dom.parentNode));){
7275 if (excludeStaticParent && parent.getStyle('position') === "static") {
7279 if (overflowRegex.test(parent.getStyle('overflow') + parent.getStyle('overflow-x') + parent.getStyle('overflow-y'))){
7283 if(parent.dom.nodeName.toLowerCase() == 'body'){
7284 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7288 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7292 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7293 * This is a shortcut for findParentNode() that always returns an Roo.Element.
7294 * @param {String} selector The simple selector to test
7295 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7296 search as a number or element (defaults to 10 || document.body)
7297 * @return {Roo.Element} The matching DOM node (or null if no match was found)
7299 up : function(simpleSelector, maxDepth){
7300 return this.findParentNode(simpleSelector, maxDepth, true);
7306 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7307 * @param {String} selector The simple selector to test
7308 * @return {Boolean} True if this element matches the selector, else false
7310 is : function(simpleSelector){
7311 return Roo.DomQuery.is(this.dom, simpleSelector);
7315 * Perform animation on this element.
7316 * @param {Object} args The YUI animation control args
7317 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7318 * @param {Function} onComplete (optional) Function to call when animation completes
7319 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7320 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7321 * @return {Roo.Element} this
7323 animate : function(args, duration, onComplete, easing, animType){
7324 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7329 * @private Internal animation call
7331 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7332 animType = animType || 'run';
7334 var anim = Roo.lib.Anim[animType](
7336 (opt.duration || defaultDur) || .35,
7337 (opt.easing || defaultEase) || 'easeOut',
7339 Roo.callback(cb, this);
7340 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7348 // private legacy anim prep
7349 preanim : function(a, i){
7350 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7354 * Removes worthless text nodes
7355 * @param {Boolean} forceReclean (optional) By default the element
7356 * keeps track if it has been cleaned already so
7357 * you can call this over and over. However, if you update the element and
7358 * need to force a reclean, you can pass true.
7360 clean : function(forceReclean){
7361 if(this.isCleaned && forceReclean !== true){
7365 var d = this.dom, n = d.firstChild, ni = -1;
7367 var nx = n.nextSibling;
7368 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7375 this.isCleaned = true;
7380 calcOffsetsTo : function(el){
7383 var restorePos = false;
7384 if(el.getStyle('position') == 'static'){
7385 el.position('relative');
7390 while(op && op != d && op.tagName != 'HTML'){
7393 op = op.offsetParent;
7396 el.position('static');
7402 * Scrolls this element into view within the passed container.
7403 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7404 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7405 * @return {Roo.Element} this
7407 scrollIntoView : function(container, hscroll){
7408 var c = Roo.getDom(container) || document.body;
7411 var o = this.calcOffsetsTo(c),
7414 b = t+el.offsetHeight,
7415 r = l+el.offsetWidth;
7417 var ch = c.clientHeight;
7418 var ct = parseInt(c.scrollTop, 10);
7419 var cl = parseInt(c.scrollLeft, 10);
7421 var cr = cl + c.clientWidth;
7429 if(hscroll !== false){
7433 c.scrollLeft = r-c.clientWidth;
7440 scrollChildIntoView : function(child, hscroll){
7441 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7445 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7446 * the new height may not be available immediately.
7447 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7448 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7449 * @param {Function} onComplete (optional) Function to call when animation completes
7450 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7451 * @return {Roo.Element} this
7453 autoHeight : function(animate, duration, onComplete, easing){
7454 var oldHeight = this.getHeight();
7456 this.setHeight(1); // force clipping
7457 setTimeout(function(){
7458 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7460 this.setHeight(height);
7462 if(typeof onComplete == "function"){
7466 this.setHeight(oldHeight); // restore original height
7467 this.setHeight(height, animate, duration, function(){
7469 if(typeof onComplete == "function") { onComplete(); }
7470 }.createDelegate(this), easing);
7472 }.createDelegate(this), 0);
7477 * Returns true if this element is an ancestor of the passed element
7478 * @param {HTMLElement/String} el The element to check
7479 * @return {Boolean} True if this element is an ancestor of el, else false
7481 contains : function(el){
7482 if(!el){return false;}
7483 return D.isAncestor(this.dom, el.dom ? el.dom : el);
7487 * Checks whether the element is currently visible using both visibility and display properties.
7488 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7489 * @return {Boolean} True if the element is currently visible, else false
7491 isVisible : function(deep) {
7492 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7493 if(deep !== true || !vis){
7496 var p = this.dom.parentNode;
7497 while(p && p.tagName.toLowerCase() != "body"){
7498 if(!Roo.fly(p, '_isVisible').isVisible()){
7507 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7508 * @param {String} selector The CSS selector
7509 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7510 * @return {CompositeElement/CompositeElementLite} The composite element
7512 select : function(selector, unique){
7513 return El.select(selector, unique, this.dom);
7517 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7518 * @param {String} selector The CSS selector
7519 * @return {Array} An array of the matched nodes
7521 query : function(selector, unique){
7522 return Roo.DomQuery.select(selector, this.dom);
7526 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7527 * @param {String} selector The CSS selector
7528 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7529 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7531 child : function(selector, returnDom){
7532 var n = Roo.DomQuery.selectNode(selector, this.dom);
7533 return returnDom ? n : Roo.get(n);
7537 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7538 * @param {String} selector The CSS selector
7539 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7540 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7542 down : function(selector, returnDom){
7543 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7544 return returnDom ? n : Roo.get(n);
7548 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7549 * @param {String} group The group the DD object is member of
7550 * @param {Object} config The DD config object
7551 * @param {Object} overrides An object containing methods to override/implement on the DD object
7552 * @return {Roo.dd.DD} The DD object
7554 initDD : function(group, config, overrides){
7555 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7556 return Roo.apply(dd, overrides);
7560 * Initializes a {@link Roo.dd.DDProxy} object for this element.
7561 * @param {String} group The group the DDProxy object is member of
7562 * @param {Object} config The DDProxy config object
7563 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7564 * @return {Roo.dd.DDProxy} The DDProxy object
7566 initDDProxy : function(group, config, overrides){
7567 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7568 return Roo.apply(dd, overrides);
7572 * Initializes a {@link Roo.dd.DDTarget} object for this element.
7573 * @param {String} group The group the DDTarget object is member of
7574 * @param {Object} config The DDTarget config object
7575 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7576 * @return {Roo.dd.DDTarget} The DDTarget object
7578 initDDTarget : function(group, config, overrides){
7579 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7580 return Roo.apply(dd, overrides);
7584 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7585 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7586 * @param {Boolean} visible Whether the element is visible
7587 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7588 * @return {Roo.Element} this
7590 setVisible : function(visible, animate){
7592 if(this.visibilityMode == El.DISPLAY){
7593 this.setDisplayed(visible);
7596 this.dom.style.visibility = visible ? "visible" : "hidden";
7599 // closure for composites
7601 var visMode = this.visibilityMode;
7603 this.setOpacity(.01);
7604 this.setVisible(true);
7606 this.anim({opacity: { to: (visible?1:0) }},
7607 this.preanim(arguments, 1),
7608 null, .35, 'easeIn', function(){
7610 if(visMode == El.DISPLAY){
7611 dom.style.display = "none";
7613 dom.style.visibility = "hidden";
7615 Roo.get(dom).setOpacity(1);
7623 * Returns true if display is not "none"
7626 isDisplayed : function() {
7627 return this.getStyle("display") != "none";
7631 * Toggles the element's visibility or display, depending on visibility mode.
7632 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7633 * @return {Roo.Element} this
7635 toggle : function(animate){
7636 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7641 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7642 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7643 * @return {Roo.Element} this
7645 setDisplayed : function(value) {
7646 if(typeof value == "boolean"){
7647 value = value ? this.originalDisplay : "none";
7649 this.setStyle("display", value);
7654 * Tries to focus the element. Any exceptions are caught and ignored.
7655 * @return {Roo.Element} this
7657 focus : function() {
7665 * Tries to blur the element. Any exceptions are caught and ignored.
7666 * @return {Roo.Element} this
7676 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7677 * @param {String/Array} className The CSS class to add, or an array of classes
7678 * @return {Roo.Element} this
7680 addClass : function(className){
7681 if(className instanceof Array){
7682 for(var i = 0, len = className.length; i < len; i++) {
7683 this.addClass(className[i]);
7686 if(className && !this.hasClass(className)){
7687 if (this.dom instanceof SVGElement) {
7688 this.dom.className.baseVal =this.dom.className.baseVal + " " + className;
7690 this.dom.className = this.dom.className + " " + className;
7698 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7699 * @param {String/Array} className The CSS class to add, or an array of classes
7700 * @return {Roo.Element} this
7702 radioClass : function(className){
7703 var siblings = this.dom.parentNode.childNodes;
7704 for(var i = 0; i < siblings.length; i++) {
7705 var s = siblings[i];
7706 if(s.nodeType == 1){
7707 Roo.get(s).removeClass(className);
7710 this.addClass(className);
7715 * Removes one or more CSS classes from the element.
7716 * @param {String/Array} className The CSS class to remove, or an array of classes
7717 * @return {Roo.Element} this
7719 removeClass : function(className){
7721 var cn = this.dom instanceof SVGElement ? this.dom.className.baseVal : this.dom.className;
7722 if(!className || !cn){
7725 if(className instanceof Array){
7726 for(var i = 0, len = className.length; i < len; i++) {
7727 this.removeClass(className[i]);
7730 if(this.hasClass(className)){
7731 var re = this.classReCache[className];
7733 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7734 this.classReCache[className] = re;
7736 if (this.dom instanceof SVGElement) {
7737 this.dom.className.baseVal = cn.replace(re, " ");
7739 this.dom.className = cn.replace(re, " ");
7750 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7751 * @param {String} className The CSS class to toggle
7752 * @return {Roo.Element} this
7754 toggleClass : function(className){
7755 if(this.hasClass(className)){
7756 this.removeClass(className);
7758 this.addClass(className);
7764 * Checks if the specified CSS class exists on this element's DOM node.
7765 * @param {String} className The CSS class to check for
7766 * @return {Boolean} True if the class exists, else false
7768 hasClass : function(className){
7769 if (this.dom instanceof SVGElement) {
7770 return className && (' '+this.dom.className.baseVal +' ').indexOf(' '+className+' ') != -1;
7772 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7776 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
7777 * @param {String} oldClassName The CSS class to replace
7778 * @param {String} newClassName The replacement CSS class
7779 * @return {Roo.Element} this
7781 replaceClass : function(oldClassName, newClassName){
7782 this.removeClass(oldClassName);
7783 this.addClass(newClassName);
7788 * Returns an object with properties matching the styles requested.
7789 * For example, el.getStyles('color', 'font-size', 'width') might return
7790 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7791 * @param {String} style1 A style name
7792 * @param {String} style2 A style name
7793 * @param {String} etc.
7794 * @return {Object} The style object
7796 getStyles : function(){
7797 var a = arguments, len = a.length, r = {};
7798 for(var i = 0; i < len; i++){
7799 r[a[i]] = this.getStyle(a[i]);
7805 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7806 * @param {String} property The style property whose value is returned.
7807 * @return {String} The current value of the style property for this element.
7809 getStyle : function(){
7810 return view && view.getComputedStyle ?
7812 var el = this.dom, v, cs, camel;
7813 if(prop == 'float'){
7816 if(el.style && (v = el.style[prop])){
7819 if(cs = view.getComputedStyle(el, "")){
7820 if(!(camel = propCache[prop])){
7821 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7828 var el = this.dom, v, cs, camel;
7829 if(prop == 'opacity'){
7830 if(typeof el.style.filter == 'string'){
7831 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7833 var fv = parseFloat(m[1]);
7835 return fv ? fv / 100 : 0;
7840 }else if(prop == 'float'){
7841 prop = "styleFloat";
7843 if(!(camel = propCache[prop])){
7844 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7846 if(v = el.style[camel]){
7849 if(cs = el.currentStyle){
7857 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7858 * @param {String/Object} property The style property to be set, or an object of multiple styles.
7859 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7860 * @return {Roo.Element} this
7862 setStyle : function(prop, value){
7863 if(typeof prop == "string"){
7865 if (prop == 'float') {
7866 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
7871 if(!(camel = propCache[prop])){
7872 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7875 if(camel == 'opacity') {
7876 this.setOpacity(value);
7878 this.dom.style[camel] = value;
7881 for(var style in prop){
7882 if(typeof prop[style] != "function"){
7883 this.setStyle(style, prop[style]);
7891 * More flexible version of {@link #setStyle} for setting style properties.
7892 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7893 * a function which returns such a specification.
7894 * @return {Roo.Element} this
7896 applyStyles : function(style){
7897 Roo.DomHelper.applyStyles(this.dom, style);
7902 * 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).
7903 * @return {Number} The X position of the element
7906 return D.getX(this.dom);
7910 * 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).
7911 * @return {Number} The Y position of the element
7914 return D.getY(this.dom);
7918 * 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).
7919 * @return {Array} The XY position of the element
7922 return D.getXY(this.dom);
7926 * 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).
7927 * @param {Number} The X position of the element
7928 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7929 * @return {Roo.Element} this
7931 setX : function(x, animate){
7933 D.setX(this.dom, x);
7935 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7941 * 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).
7942 * @param {Number} The Y position of the element
7943 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7944 * @return {Roo.Element} this
7946 setY : function(y, animate){
7948 D.setY(this.dom, y);
7950 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7956 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7957 * @param {String} left The left CSS property value
7958 * @return {Roo.Element} this
7960 setLeft : function(left){
7961 this.setStyle("left", this.addUnits(left));
7966 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7967 * @param {String} top The top CSS property value
7968 * @return {Roo.Element} this
7970 setTop : function(top){
7971 this.setStyle("top", this.addUnits(top));
7976 * Sets the element's CSS right style.
7977 * @param {String} right The right CSS property value
7978 * @return {Roo.Element} this
7980 setRight : function(right){
7981 this.setStyle("right", this.addUnits(right));
7986 * Sets the element's CSS bottom style.
7987 * @param {String} bottom The bottom CSS property value
7988 * @return {Roo.Element} this
7990 setBottom : function(bottom){
7991 this.setStyle("bottom", this.addUnits(bottom));
7996 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7997 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7998 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7999 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8000 * @return {Roo.Element} this
8002 setXY : function(pos, animate){
8004 D.setXY(this.dom, pos);
8006 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
8012 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
8013 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
8014 * @param {Number} x X value for new position (coordinates are page-based)
8015 * @param {Number} y Y value for new position (coordinates are page-based)
8016 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8017 * @return {Roo.Element} this
8019 setLocation : function(x, y, animate){
8020 this.setXY([x, y], this.preanim(arguments, 2));
8025 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
8026 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
8027 * @param {Number} x X value for new position (coordinates are page-based)
8028 * @param {Number} y Y value for new position (coordinates are page-based)
8029 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8030 * @return {Roo.Element} this
8032 moveTo : function(x, y, animate){
8033 this.setXY([x, y], this.preanim(arguments, 2));
8038 * Returns the region of the given element.
8039 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
8040 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
8042 getRegion : function(){
8043 return D.getRegion(this.dom);
8047 * Returns the offset height of the element
8048 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
8049 * @return {Number} The element's height
8051 getHeight : function(contentHeight){
8052 var h = this.dom.offsetHeight || 0;
8053 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
8057 * Returns the offset width of the element
8058 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
8059 * @return {Number} The element's width
8061 getWidth : function(contentWidth){
8062 var w = this.dom.offsetWidth || 0;
8063 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
8067 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
8068 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
8069 * if a height has not been set using CSS.
8072 getComputedHeight : function(){
8073 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
8075 h = parseInt(this.getStyle('height'), 10) || 0;
8076 if(!this.isBorderBox()){
8077 h += this.getFrameWidth('tb');
8084 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
8085 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
8086 * if a width has not been set using CSS.
8089 getComputedWidth : function(){
8090 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
8092 w = parseInt(this.getStyle('width'), 10) || 0;
8093 if(!this.isBorderBox()){
8094 w += this.getFrameWidth('lr');
8101 * Returns the size of the element.
8102 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
8103 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
8105 getSize : function(contentSize){
8106 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
8110 * Returns the width and height of the viewport.
8111 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
8113 getViewSize : function(){
8114 var d = this.dom, doc = document, aw = 0, ah = 0;
8115 if(d == doc || d == doc.body){
8116 return {width : D.getViewWidth(), height: D.getViewHeight()};
8119 width : d.clientWidth,
8120 height: d.clientHeight
8126 * Returns the value of the "value" attribute
8127 * @param {Boolean} asNumber true to parse the value as a number
8128 * @return {String/Number}
8130 getValue : function(asNumber){
8131 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
8135 adjustWidth : function(width){
8136 if(typeof width == "number"){
8137 if(this.autoBoxAdjust && !this.isBorderBox()){
8138 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8148 adjustHeight : function(height){
8149 if(typeof height == "number"){
8150 if(this.autoBoxAdjust && !this.isBorderBox()){
8151 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8161 * Set the width of the element
8162 * @param {Number} width The new width
8163 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8164 * @return {Roo.Element} this
8166 setWidth : function(width, animate){
8167 width = this.adjustWidth(width);
8169 this.dom.style.width = this.addUnits(width);
8171 this.anim({width: {to: width}}, this.preanim(arguments, 1));
8177 * Set the height of the element
8178 * @param {Number} height The new height
8179 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8180 * @return {Roo.Element} this
8182 setHeight : function(height, animate){
8183 height = this.adjustHeight(height);
8185 this.dom.style.height = this.addUnits(height);
8187 this.anim({height: {to: height}}, this.preanim(arguments, 1));
8193 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
8194 * @param {Number} width The new width
8195 * @param {Number} height The new height
8196 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8197 * @return {Roo.Element} this
8199 setSize : function(width, height, animate){
8200 if(typeof width == "object"){ // in case of object from getSize()
8201 height = width.height; width = width.width;
8203 width = this.adjustWidth(width); height = this.adjustHeight(height);
8205 this.dom.style.width = this.addUnits(width);
8206 this.dom.style.height = this.addUnits(height);
8208 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
8214 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
8215 * @param {Number} x X value for new position (coordinates are page-based)
8216 * @param {Number} y Y value for new position (coordinates are page-based)
8217 * @param {Number} width The new width
8218 * @param {Number} height The new height
8219 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8220 * @return {Roo.Element} this
8222 setBounds : function(x, y, width, height, animate){
8224 this.setSize(width, height);
8225 this.setLocation(x, y);
8227 width = this.adjustWidth(width); height = this.adjustHeight(height);
8228 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
8229 this.preanim(arguments, 4), 'motion');
8235 * 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.
8236 * @param {Roo.lib.Region} region The region to fill
8237 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8238 * @return {Roo.Element} this
8240 setRegion : function(region, animate){
8241 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
8246 * Appends an event handler
8248 * @param {String} eventName The type of event to append
8249 * @param {Function} fn The method the event invokes
8250 * @param {Object} scope (optional) The scope (this object) of the fn
8251 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
8253 addListener : function(eventName, fn, scope, options)
8255 if (eventName == 'dblclick') { // doublclick (touchstart) - faked on touch.
8256 this.addListener('touchstart', this.onTapHandler, this);
8259 // we need to handle a special case where dom element is a svg element.
8260 // in this case we do not actua
8265 if (this.dom instanceof SVGElement && !(this.dom instanceof SVGSVGElement)) {
8266 if (typeof(this.listeners[eventName]) == 'undefined') {
8267 this.listeners[eventName] = new Roo.util.Event(this, eventName);
8269 this.listeners[eventName].addListener(fn, scope, options);
8274 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
8279 onTapHandler : function(event)
8281 if(!this.tapedTwice) {
8282 this.tapedTwice = true;
8284 setTimeout( function() {
8285 s.tapedTwice = false;
8289 event.preventDefault();
8290 var revent = new MouseEvent('dblclick', {
8296 this.dom.dispatchEvent(revent);
8297 //action on double tap goes below
8302 * Removes an event handler from this element
8303 * @param {String} eventName the type of event to remove
8304 * @param {Function} fn the method the event invokes
8305 * @param {Function} scope (needed for svg fake listeners)
8306 * @return {Roo.Element} this
8308 removeListener : function(eventName, fn, scope){
8309 Roo.EventManager.removeListener(this.dom, eventName, fn);
8310 if (typeof(this.listeners) == 'undefined' || typeof(this.listeners[eventName]) == 'undefined') {
8313 this.listeners[eventName].removeListener(fn, scope);
8318 * Removes all previous added listeners from this element
8319 * @return {Roo.Element} this
8321 removeAllListeners : function(){
8322 E.purgeElement(this.dom);
8323 this.listeners = {};
8327 relayEvent : function(eventName, observable){
8328 this.on(eventName, function(e){
8329 observable.fireEvent(eventName, e);
8335 * Set the opacity of the element
8336 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8337 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8338 * @return {Roo.Element} this
8340 setOpacity : function(opacity, animate){
8342 var s = this.dom.style;
8345 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8346 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8348 s.opacity = opacity;
8351 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8357 * Gets the left X coordinate
8358 * @param {Boolean} local True to get the local css position instead of page coordinate
8361 getLeft : function(local){
8365 return parseInt(this.getStyle("left"), 10) || 0;
8370 * Gets the right X coordinate of the element (element X position + element width)
8371 * @param {Boolean} local True to get the local css position instead of page coordinate
8374 getRight : function(local){
8376 return this.getX() + this.getWidth();
8378 return (this.getLeft(true) + this.getWidth()) || 0;
8383 * Gets the top Y coordinate
8384 * @param {Boolean} local True to get the local css position instead of page coordinate
8387 getTop : function(local) {
8391 return parseInt(this.getStyle("top"), 10) || 0;
8396 * Gets the bottom Y coordinate of the element (element Y position + element height)
8397 * @param {Boolean} local True to get the local css position instead of page coordinate
8400 getBottom : function(local){
8402 return this.getY() + this.getHeight();
8404 return (this.getTop(true) + this.getHeight()) || 0;
8409 * Initializes positioning on this element. If a desired position is not passed, it will make the
8410 * the element positioned relative IF it is not already positioned.
8411 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8412 * @param {Number} zIndex (optional) The zIndex to apply
8413 * @param {Number} x (optional) Set the page X position
8414 * @param {Number} y (optional) Set the page Y position
8416 position : function(pos, zIndex, x, y){
8418 if(this.getStyle('position') == 'static'){
8419 this.setStyle('position', 'relative');
8422 this.setStyle("position", pos);
8425 this.setStyle("z-index", zIndex);
8427 if(x !== undefined && y !== undefined){
8429 }else if(x !== undefined){
8431 }else if(y !== undefined){
8437 * Clear positioning back to the default when the document was loaded
8438 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8439 * @return {Roo.Element} this
8441 clearPositioning : function(value){
8449 "position" : "static"
8455 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8456 * snapshot before performing an update and then restoring the element.
8459 getPositioning : function(){
8460 var l = this.getStyle("left");
8461 var t = this.getStyle("top");
8463 "position" : this.getStyle("position"),
8465 "right" : l ? "" : this.getStyle("right"),
8467 "bottom" : t ? "" : this.getStyle("bottom"),
8468 "z-index" : this.getStyle("z-index")
8473 * Gets the width of the border(s) for the specified side(s)
8474 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8475 * passing lr would get the border (l)eft width + the border (r)ight width.
8476 * @return {Number} The width of the sides passed added together
8478 getBorderWidth : function(side){
8479 return this.addStyles(side, El.borders);
8483 * Gets the width of the padding(s) for the specified side(s)
8484 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8485 * passing lr would get the padding (l)eft + the padding (r)ight.
8486 * @return {Number} The padding of the sides passed added together
8488 getPadding : function(side){
8489 return this.addStyles(side, El.paddings);
8493 * Set positioning with an object returned by getPositioning().
8494 * @param {Object} posCfg
8495 * @return {Roo.Element} this
8497 setPositioning : function(pc){
8498 this.applyStyles(pc);
8499 if(pc.right == "auto"){
8500 this.dom.style.right = "";
8502 if(pc.bottom == "auto"){
8503 this.dom.style.bottom = "";
8509 fixDisplay : function(){
8510 if(this.getStyle("display") == "none"){
8511 this.setStyle("visibility", "hidden");
8512 this.setStyle("display", this.originalDisplay); // first try reverting to default
8513 if(this.getStyle("display") == "none"){ // if that fails, default to block
8514 this.setStyle("display", "block");
8520 * Quick set left and top adding default units
8521 * @param {String} left The left CSS property value
8522 * @param {String} top The top CSS property value
8523 * @return {Roo.Element} this
8525 setLeftTop : function(left, top){
8526 this.dom.style.left = this.addUnits(left);
8527 this.dom.style.top = this.addUnits(top);
8532 * Move this element relative to its current position.
8533 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8534 * @param {Number} distance How far to move the element in pixels
8535 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8536 * @return {Roo.Element} this
8538 move : function(direction, distance, animate){
8539 var xy = this.getXY();
8540 direction = direction.toLowerCase();
8544 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8548 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8553 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8558 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8565 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8566 * @return {Roo.Element} this
8569 if(!this.isClipped){
8570 this.isClipped = true;
8571 this.originalClip = {
8572 "o": this.getStyle("overflow"),
8573 "x": this.getStyle("overflow-x"),
8574 "y": this.getStyle("overflow-y")
8576 this.setStyle("overflow", "hidden");
8577 this.setStyle("overflow-x", "hidden");
8578 this.setStyle("overflow-y", "hidden");
8584 * Return clipping (overflow) to original clipping before clip() was called
8585 * @return {Roo.Element} this
8587 unclip : function(){
8589 this.isClipped = false;
8590 var o = this.originalClip;
8591 if(o.o){this.setStyle("overflow", o.o);}
8592 if(o.x){this.setStyle("overflow-x", o.x);}
8593 if(o.y){this.setStyle("overflow-y", o.y);}
8600 * Gets the x,y coordinates specified by the anchor position on the element.
8601 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
8602 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8603 * {width: (target width), height: (target height)} (defaults to the element's current size)
8604 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8605 * @return {Array} [x, y] An array containing the element's x and y coordinates
8607 getAnchorXY : function(anchor, local, s){
8608 //Passing a different size is useful for pre-calculating anchors,
8609 //especially for anchored animations that change the el size.
8611 var w, h, vp = false;
8614 if(d == document.body || d == document){
8616 w = D.getViewWidth(); h = D.getViewHeight();
8618 w = this.getWidth(); h = this.getHeight();
8621 w = s.width; h = s.height;
8623 var x = 0, y = 0, r = Math.round;
8624 switch((anchor || "tl").toLowerCase()){
8666 var sc = this.getScroll();
8667 return [x + sc.left, y + sc.top];
8669 //Add the element's offset xy
8670 var o = this.getXY();
8671 return [x+o[0], y+o[1]];
8675 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8676 * supported position values.
8677 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8678 * @param {String} position The position to align to.
8679 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8680 * @return {Array} [x, y]
8682 getAlignToXY : function(el, p, o)
8687 throw "Element.alignTo with an element that doesn't exist";
8689 var c = false; //constrain to viewport
8690 var p1 = "", p2 = "";
8697 }else if(p.indexOf("-") == -1){
8700 p = p.toLowerCase();
8701 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8703 throw "Element.alignTo with an invalid alignment " + p;
8705 p1 = m[1]; p2 = m[2]; c = !!m[3];
8707 //Subtract the aligned el's internal xy from the target's offset xy
8708 //plus custom offset to get the aligned el's new offset xy
8709 var a1 = this.getAnchorXY(p1, true);
8710 var a2 = el.getAnchorXY(p2, false);
8711 var x = a2[0] - a1[0] + o[0];
8712 var y = a2[1] - a1[1] + o[1];
8714 //constrain the aligned el to viewport if necessary
8715 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8716 // 5px of margin for ie
8717 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8719 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8720 //perpendicular to the vp border, allow the aligned el to slide on that border,
8721 //otherwise swap the aligned el to the opposite border of the target.
8722 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8723 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8724 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t") );
8725 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8728 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8729 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8731 if((x+w) > dw + scrollX){
8732 x = swapX ? r.left-w : dw+scrollX-w;
8735 x = swapX ? r.right : scrollX;
8737 if((y+h) > dh + scrollY){
8738 y = swapY ? r.top-h : dh+scrollY-h;
8741 y = swapY ? r.bottom : scrollY;
8748 getConstrainToXY : function(){
8749 var os = {top:0, left:0, bottom:0, right: 0};
8751 return function(el, local, offsets, proposedXY){
8753 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8755 var vw, vh, vx = 0, vy = 0;
8756 if(el.dom == document.body || el.dom == document){
8757 vw = Roo.lib.Dom.getViewWidth();
8758 vh = Roo.lib.Dom.getViewHeight();
8760 vw = el.dom.clientWidth;
8761 vh = el.dom.clientHeight;
8763 var vxy = el.getXY();
8769 var s = el.getScroll();
8771 vx += offsets.left + s.left;
8772 vy += offsets.top + s.top;
8774 vw -= offsets.right;
8775 vh -= offsets.bottom;
8780 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8781 var x = xy[0], y = xy[1];
8782 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8784 // only move it if it needs it
8787 // first validate right/bottom
8796 // then make sure top/left isn't negative
8805 return moved ? [x, y] : false;
8810 adjustForConstraints : function(xy, parent, offsets){
8811 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
8815 * Aligns this element with another element relative to the specified anchor points. If the other element is the
8816 * document it aligns it to the viewport.
8817 * The position parameter is optional, and can be specified in any one of the following formats:
8819 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8820 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8821 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
8822 * deprecated in favor of the newer two anchor syntax below</i>.</li>
8823 * <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
8824 * element's anchor point, and the second value is used as the target's anchor point.</li>
8826 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
8827 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8828 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
8829 * that specified in order to enforce the viewport constraints.
8830 * Following are all of the supported anchor positions:
8833 ----- -----------------------------
8834 tl The top left corner (default)
8835 t The center of the top edge
8836 tr The top right corner
8837 l The center of the left edge
8838 c In the center of the element
8839 r The center of the right edge
8840 bl The bottom left corner
8841 b The center of the bottom edge
8842 br The bottom right corner
8846 // align el to other-el using the default positioning ("tl-bl", non-constrained)
8847 el.alignTo("other-el");
8849 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8850 el.alignTo("other-el", "tr?");
8852 // align the bottom right corner of el with the center left edge of other-el
8853 el.alignTo("other-el", "br-l?");
8855 // align the center of el with the bottom left corner of other-el and
8856 // adjust the x position by -6 pixels (and the y position by 0)
8857 el.alignTo("other-el", "c-bl", [-6, 0]);
8859 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8860 * @param {String} position The position to align to.
8861 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8862 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8863 * @return {Roo.Element} this
8865 alignTo : function(element, position, offsets, animate){
8866 var xy = this.getAlignToXY(element, position, offsets);
8867 this.setXY(xy, this.preanim(arguments, 3));
8872 * Anchors an element to another element and realigns it when the window is resized.
8873 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8874 * @param {String} position The position to align to.
8875 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8876 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8877 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8878 * is a number, it is used as the buffer delay (defaults to 50ms).
8879 * @param {Function} callback The function to call after the animation finishes
8880 * @return {Roo.Element} this
8882 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8883 var action = function(){
8884 this.alignTo(el, alignment, offsets, animate);
8885 Roo.callback(callback, this);
8887 Roo.EventManager.onWindowResize(action, this);
8888 var tm = typeof monitorScroll;
8889 if(tm != 'undefined'){
8890 Roo.EventManager.on(window, 'scroll', action, this,
8891 {buffer: tm == 'number' ? monitorScroll : 50});
8893 action.call(this); // align immediately
8897 * Clears any opacity settings from this element. Required in some cases for IE.
8898 * @return {Roo.Element} this
8900 clearOpacity : function(){
8901 if (window.ActiveXObject) {
8902 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8903 this.dom.style.filter = "";
8906 this.dom.style.opacity = "";
8907 this.dom.style["-moz-opacity"] = "";
8908 this.dom.style["-khtml-opacity"] = "";
8914 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8915 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8916 * @return {Roo.Element} this
8918 hide : function(animate){
8919 this.setVisible(false, this.preanim(arguments, 0));
8924 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8925 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8926 * @return {Roo.Element} this
8928 show : function(animate){
8929 this.setVisible(true, this.preanim(arguments, 0));
8934 * @private Test if size has a unit, otherwise appends the default
8936 addUnits : function(size){
8937 return Roo.Element.addUnits(size, this.defaultUnit);
8941 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8942 * @return {Roo.Element} this
8944 beginMeasure : function(){
8946 if(el.offsetWidth || el.offsetHeight){
8947 return this; // offsets work already
8950 var p = this.dom, b = document.body; // start with this element
8951 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8952 var pe = Roo.get(p);
8953 if(pe.getStyle('display') == 'none'){
8954 changed.push({el: p, visibility: pe.getStyle("visibility")});
8955 p.style.visibility = "hidden";
8956 p.style.display = "block";
8960 this._measureChanged = changed;
8966 * Restores displays to before beginMeasure was called
8967 * @return {Roo.Element} this
8969 endMeasure : function(){
8970 var changed = this._measureChanged;
8972 for(var i = 0, len = changed.length; i < len; i++) {
8974 r.el.style.visibility = r.visibility;
8975 r.el.style.display = "none";
8977 this._measureChanged = null;
8983 * Update the innerHTML of this element, optionally searching for and processing scripts
8984 * @param {String} html The new HTML
8985 * @param {Boolean} loadScripts (optional) true to look for and process scripts
8986 * @param {Function} callback For async script loading you can be noticed when the update completes
8987 * @return {Roo.Element} this
8989 update : function(html, loadScripts, callback){
8990 if(typeof html == "undefined"){
8993 if(loadScripts !== true){
8994 this.dom.innerHTML = html;
8995 if(typeof callback == "function"){
9003 html += '<span id="' + id + '"></span>';
9005 E.onAvailable(id, function(){
9006 var hd = document.getElementsByTagName("head")[0];
9007 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
9008 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
9009 var typeRe = /\stype=([\'\"])(.*?)\1/i;
9012 while(match = re.exec(html)){
9013 var attrs = match[1];
9014 var srcMatch = attrs ? attrs.match(srcRe) : false;
9015 if(srcMatch && srcMatch[2]){
9016 var s = document.createElement("script");
9017 s.src = srcMatch[2];
9018 var typeMatch = attrs.match(typeRe);
9019 if(typeMatch && typeMatch[2]){
9020 s.type = typeMatch[2];
9023 }else if(match[2] && match[2].length > 0){
9024 if(window.execScript) {
9025 window.execScript(match[2]);
9033 window.eval(match[2]);
9037 var el = document.getElementById(id);
9038 if(el){el.parentNode.removeChild(el);}
9039 if(typeof callback == "function"){
9043 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
9048 * Direct access to the UpdateManager update() method (takes the same parameters).
9049 * @param {String/Function} url The url for this request or a function to call to get the url
9050 * @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}
9051 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
9052 * @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.
9053 * @return {Roo.Element} this
9056 var um = this.getUpdateManager();
9057 um.update.apply(um, arguments);
9062 * Gets this element's UpdateManager
9063 * @return {Roo.UpdateManager} The UpdateManager
9065 getUpdateManager : function(){
9066 if(!this.updateManager){
9067 this.updateManager = new Roo.UpdateManager(this);
9069 return this.updateManager;
9073 * Disables text selection for this element (normalized across browsers)
9074 * @return {Roo.Element} this
9076 unselectable : function(){
9077 this.dom.unselectable = "on";
9078 this.swallowEvent("selectstart", true);
9079 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
9080 this.addClass("x-unselectable");
9085 * Calculates the x, y to center this element on the screen
9086 * @return {Array} The x, y values [x, y]
9088 getCenterXY : function(){
9089 return this.getAlignToXY(document, 'c-c');
9093 * Centers the Element in either the viewport, or another Element.
9094 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
9096 center : function(centerIn){
9097 this.alignTo(centerIn || document, 'c-c');
9102 * Tests various css rules/browsers to determine if this element uses a border box
9105 isBorderBox : function(){
9106 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
9110 * Return a box {x, y, width, height} that can be used to set another elements
9111 * size/location to match this element.
9112 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
9113 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
9114 * @return {Object} box An object in the format {x, y, width, height}
9116 getBox : function(contentBox, local){
9121 var left = parseInt(this.getStyle("left"), 10) || 0;
9122 var top = parseInt(this.getStyle("top"), 10) || 0;
9125 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
9127 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
9129 var l = this.getBorderWidth("l")+this.getPadding("l");
9130 var r = this.getBorderWidth("r")+this.getPadding("r");
9131 var t = this.getBorderWidth("t")+this.getPadding("t");
9132 var b = this.getBorderWidth("b")+this.getPadding("b");
9133 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)};
9135 bx.right = bx.x + bx.width;
9136 bx.bottom = bx.y + bx.height;
9141 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
9142 for more information about the sides.
9143 * @param {String} sides
9146 getFrameWidth : function(sides, onlyContentBox){
9147 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
9151 * 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.
9152 * @param {Object} box The box to fill {x, y, width, height}
9153 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
9154 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9155 * @return {Roo.Element} this
9157 setBox : function(box, adjust, animate){
9158 var w = box.width, h = box.height;
9159 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
9160 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
9161 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
9163 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
9168 * Forces the browser to repaint this element
9169 * @return {Roo.Element} this
9171 repaint : function(){
9173 this.addClass("x-repaint");
9174 setTimeout(function(){
9175 Roo.get(dom).removeClass("x-repaint");
9181 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
9182 * then it returns the calculated width of the sides (see getPadding)
9183 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
9184 * @return {Object/Number}
9186 getMargins : function(side){
9189 top: parseInt(this.getStyle("margin-top"), 10) || 0,
9190 left: parseInt(this.getStyle("margin-left"), 10) || 0,
9191 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
9192 right: parseInt(this.getStyle("margin-right"), 10) || 0
9195 return this.addStyles(side, El.margins);
9200 addStyles : function(sides, styles){
9202 for(var i = 0, len = sides.length; i < len; i++){
9203 v = this.getStyle(styles[sides.charAt(i)]);
9205 w = parseInt(v, 10);
9213 * Creates a proxy element of this element
9214 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
9215 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
9216 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
9217 * @return {Roo.Element} The new proxy element
9219 createProxy : function(config, renderTo, matchBox){
9221 renderTo = Roo.getDom(renderTo);
9223 renderTo = document.body;
9225 config = typeof config == "object" ?
9226 config : {tag : "div", cls: config};
9227 var proxy = Roo.DomHelper.append(renderTo, config, true);
9229 proxy.setBox(this.getBox());
9235 * Puts a mask over this element to disable user interaction. Requires core.css.
9236 * This method can only be applied to elements which accept child nodes.
9237 * @param {String} msg (optional) A message to display in the mask
9238 * @param {String} msgCls (optional) A css class to apply to the msg element
9239 * @return {Element} The mask element
9241 mask : function(msg, msgCls)
9243 if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
9244 this.setStyle("position", "relative");
9247 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
9250 this.addClass("x-masked");
9251 this._mask.setDisplayed(true);
9256 while (dom && dom.style) {
9257 if (!isNaN(parseInt(dom.style.zIndex))) {
9258 z = Math.max(z, parseInt(dom.style.zIndex));
9260 dom = dom.parentNode;
9262 // if we are masking the body - then it hides everything..
9263 if (this.dom == document.body) {
9265 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
9266 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
9269 if(typeof msg == 'string'){
9271 this._maskMsg = Roo.DomHelper.append(this.dom, {
9272 cls: "roo-el-mask-msg",
9276 cls: 'fa fa-spinner fa-spin'
9284 var mm = this._maskMsg;
9285 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
9286 if (mm.dom.lastChild) { // weird IE issue?
9287 mm.dom.lastChild.innerHTML = msg;
9289 mm.setDisplayed(true);
9291 mm.setStyle('z-index', z + 102);
9293 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
9294 this._mask.setHeight(this.getHeight());
9296 this._mask.setStyle('z-index', z + 100);
9302 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
9303 * it is cached for reuse.
9305 unmask : function(removeEl){
9307 if(removeEl === true){
9308 this._mask.remove();
9311 this._maskMsg.remove();
9312 delete this._maskMsg;
9315 this._mask.setDisplayed(false);
9317 this._maskMsg.setDisplayed(false);
9321 this.removeClass("x-masked");
9325 * Returns true if this element is masked
9328 isMasked : function(){
9329 return this._mask && this._mask.isVisible();
9333 * Creates an iframe shim for this element to keep selects and other windowed objects from
9335 * @return {Roo.Element} The new shim element
9337 createShim : function(){
9338 var el = document.createElement('iframe');
9339 el.frameBorder = 'no';
9340 el.className = 'roo-shim';
9341 if(Roo.isIE && Roo.isSecure){
9342 el.src = Roo.SSL_SECURE_URL;
9344 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9345 shim.autoBoxAdjust = false;
9350 * Removes this element from the DOM and deletes it from the cache
9352 remove : function(){
9353 if(this.dom.parentNode){
9354 this.dom.parentNode.removeChild(this.dom);
9356 delete El.cache[this.dom.id];
9360 * Sets up event handlers to add and remove a css class when the mouse is over this element
9361 * @param {String} className
9362 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9363 * mouseout events for children elements
9364 * @return {Roo.Element} this
9366 addClassOnOver : function(className, preventFlicker){
9367 this.on("mouseover", function(){
9368 Roo.fly(this, '_internal').addClass(className);
9370 var removeFn = function(e){
9371 if(preventFlicker !== true || !e.within(this, true)){
9372 Roo.fly(this, '_internal').removeClass(className);
9375 this.on("mouseout", removeFn, this.dom);
9380 * Sets up event handlers to add and remove a css class when this element has the focus
9381 * @param {String} className
9382 * @return {Roo.Element} this
9384 addClassOnFocus : function(className){
9385 this.on("focus", function(){
9386 Roo.fly(this, '_internal').addClass(className);
9388 this.on("blur", function(){
9389 Roo.fly(this, '_internal').removeClass(className);
9394 * 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)
9395 * @param {String} className
9396 * @return {Roo.Element} this
9398 addClassOnClick : function(className){
9400 this.on("mousedown", function(){
9401 Roo.fly(dom, '_internal').addClass(className);
9402 var d = Roo.get(document);
9403 var fn = function(){
9404 Roo.fly(dom, '_internal').removeClass(className);
9405 d.removeListener("mouseup", fn);
9407 d.on("mouseup", fn);
9413 * Stops the specified event from bubbling and optionally prevents the default action
9414 * @param {String} eventName
9415 * @param {Boolean} preventDefault (optional) true to prevent the default action too
9416 * @return {Roo.Element} this
9418 swallowEvent : function(eventName, preventDefault){
9419 var fn = function(e){
9420 e.stopPropagation();
9425 if(eventName instanceof Array){
9426 for(var i = 0, len = eventName.length; i < len; i++){
9427 this.on(eventName[i], fn);
9431 this.on(eventName, fn);
9438 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9441 * Sizes this element to its parent element's dimensions performing
9442 * neccessary box adjustments.
9443 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9444 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9445 * @return {Roo.Element} this
9447 fitToParent : function(monitorResize, targetParent) {
9448 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9449 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9450 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9453 var p = Roo.get(targetParent || this.dom.parentNode);
9454 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9455 if (monitorResize === true) {
9456 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9457 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9463 * Gets the next sibling, skipping text nodes
9464 * @return {HTMLElement} The next sibling or null
9466 getNextSibling : function(){
9467 var n = this.dom.nextSibling;
9468 while(n && n.nodeType != 1){
9475 * Gets the previous sibling, skipping text nodes
9476 * @return {HTMLElement} The previous sibling or null
9478 getPrevSibling : function(){
9479 var n = this.dom.previousSibling;
9480 while(n && n.nodeType != 1){
9481 n = n.previousSibling;
9488 * Appends the passed element(s) to this element
9489 * @param {String/HTMLElement/Array/Element/CompositeElement} el
9490 * @return {Roo.Element} this
9492 appendChild: function(el){
9499 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9500 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
9501 * automatically generated with the specified attributes.
9502 * @param {HTMLElement} insertBefore (optional) a child element of this element
9503 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9504 * @return {Roo.Element} The new child element
9506 createChild: function(config, insertBefore, returnDom){
9507 config = config || {tag:'div'};
9509 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9511 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
9515 * Appends this element to the passed element
9516 * @param {String/HTMLElement/Element} el The new parent element
9517 * @return {Roo.Element} this
9519 appendTo: function(el){
9520 el = Roo.getDom(el);
9521 el.appendChild(this.dom);
9526 * Inserts this element before the passed element in the DOM
9527 * @param {String/HTMLElement/Element} el The element to insert before
9528 * @return {Roo.Element} this
9530 insertBefore: function(el){
9531 el = Roo.getDom(el);
9532 el.parentNode.insertBefore(this.dom, el);
9537 * Inserts this element after the passed element in the DOM
9538 * @param {String/HTMLElement/Element} el The element to insert after
9539 * @return {Roo.Element} this
9541 insertAfter: function(el){
9542 el = Roo.getDom(el);
9543 el.parentNode.insertBefore(this.dom, el.nextSibling);
9548 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9549 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9550 * @return {Roo.Element} The new child
9552 insertFirst: function(el, returnDom){
9554 if(typeof el == 'object' && !el.nodeType){ // dh config
9555 return this.createChild(el, this.dom.firstChild, returnDom);
9557 el = Roo.getDom(el);
9558 this.dom.insertBefore(el, this.dom.firstChild);
9559 return !returnDom ? Roo.get(el) : el;
9564 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9565 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9566 * @param {String} where (optional) 'before' or 'after' defaults to before
9567 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9568 * @return {Roo.Element} the inserted Element
9570 insertSibling: function(el, where, returnDom){
9571 where = where ? where.toLowerCase() : 'before';
9573 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9575 if(typeof el == 'object' && !el.nodeType){ // dh config
9576 if(where == 'after' && !this.dom.nextSibling){
9577 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9579 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9583 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9584 where == 'before' ? this.dom : this.dom.nextSibling);
9593 * Creates and wraps this element with another element
9594 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9595 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9596 * @return {HTMLElement/Element} The newly created wrapper element
9598 wrap: function(config, returnDom){
9600 config = {tag: "div"};
9602 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9603 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9608 * Replaces the passed element with this element
9609 * @param {String/HTMLElement/Element} el The element to replace
9610 * @return {Roo.Element} this
9612 replace: function(el){
9614 this.insertBefore(el);
9620 * Inserts an html fragment into this element
9621 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9622 * @param {String} html The HTML fragment
9623 * @param {Boolean} returnEl True to return an Roo.Element
9624 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9626 insertHtml : function(where, html, returnEl){
9627 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9628 return returnEl ? Roo.get(el) : el;
9632 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9633 * @param {Object} o The object with the attributes
9634 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9635 * @return {Roo.Element} this
9637 set : function(o, useSet){
9639 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9641 if(attr == "style" || typeof o[attr] == "function") { continue; }
9643 el.className = o["cls"];
9646 el.setAttribute(attr, o[attr]);
9653 Roo.DomHelper.applyStyles(el, o.style);
9659 * Convenience method for constructing a KeyMap
9660 * @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:
9661 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9662 * @param {Function} fn The function to call
9663 * @param {Object} scope (optional) The scope of the function
9664 * @return {Roo.KeyMap} The KeyMap created
9666 addKeyListener : function(key, fn, scope){
9668 if(typeof key != "object" || key instanceof Array){
9684 return new Roo.KeyMap(this, config);
9688 * Creates a KeyMap for this element
9689 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9690 * @return {Roo.KeyMap} The KeyMap created
9692 addKeyMap : function(config){
9693 return new Roo.KeyMap(this, config);
9697 * Returns true if this element is scrollable.
9700 isScrollable : function(){
9702 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9706 * 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().
9707 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9708 * @param {Number} value The new scroll value
9709 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9710 * @return {Element} this
9713 scrollTo : function(side, value, animate){
9714 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9716 this.dom[prop] = value;
9718 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9719 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9725 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9726 * within this element's scrollable range.
9727 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9728 * @param {Number} distance How far to scroll the element in pixels
9729 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9730 * @return {Boolean} Returns true if a scroll was triggered or false if the element
9731 * was scrolled as far as it could go.
9733 scroll : function(direction, distance, animate){
9734 if(!this.isScrollable()){
9738 var l = el.scrollLeft, t = el.scrollTop;
9739 var w = el.scrollWidth, h = el.scrollHeight;
9740 var cw = el.clientWidth, ch = el.clientHeight;
9741 direction = direction.toLowerCase();
9742 var scrolled = false;
9743 var a = this.preanim(arguments, 2);
9748 var v = Math.min(l + distance, w-cw);
9749 this.scrollTo("left", v, a);
9756 var v = Math.max(l - distance, 0);
9757 this.scrollTo("left", v, a);
9765 var v = Math.max(t - distance, 0);
9766 this.scrollTo("top", v, a);
9774 var v = Math.min(t + distance, h-ch);
9775 this.scrollTo("top", v, a);
9784 * Translates the passed page coordinates into left/top css values for this element
9785 * @param {Number/Array} x The page x or an array containing [x, y]
9786 * @param {Number} y The page y
9787 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9789 translatePoints : function(x, y){
9790 if(typeof x == 'object' || x instanceof Array){
9793 var p = this.getStyle('position');
9794 var o = this.getXY();
9796 var l = parseInt(this.getStyle('left'), 10);
9797 var t = parseInt(this.getStyle('top'), 10);
9800 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9803 t = (p == "relative") ? 0 : this.dom.offsetTop;
9806 return {left: (x - o[0] + l), top: (y - o[1] + t)};
9810 * Returns the current scroll position of the element.
9811 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9813 getScroll : function(){
9814 var d = this.dom, doc = document;
9815 if(d == doc || d == doc.body){
9816 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9817 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9818 return {left: l, top: t};
9820 return {left: d.scrollLeft, top: d.scrollTop};
9825 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9826 * are convert to standard 6 digit hex color.
9827 * @param {String} attr The css attribute
9828 * @param {String} defaultValue The default value to use when a valid color isn't found
9829 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9832 getColor : function(attr, defaultValue, prefix){
9833 var v = this.getStyle(attr);
9834 if(!v || v == "transparent" || v == "inherit") {
9835 return defaultValue;
9837 var color = typeof prefix == "undefined" ? "#" : prefix;
9838 if(v.substr(0, 4) == "rgb("){
9839 var rvs = v.slice(4, v.length -1).split(",");
9840 for(var i = 0; i < 3; i++){
9841 var h = parseInt(rvs[i]).toString(16);
9848 if(v.substr(0, 1) == "#"){
9850 for(var i = 1; i < 4; i++){
9851 var c = v.charAt(i);
9854 }else if(v.length == 7){
9855 color += v.substr(1);
9859 return(color.length > 5 ? color.toLowerCase() : defaultValue);
9863 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9864 * gradient background, rounded corners and a 4-way shadow.
9865 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9866 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9867 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9868 * @return {Roo.Element} this
9870 boxWrap : function(cls){
9871 cls = cls || 'x-box';
9872 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9873 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9878 * Returns the value of a namespaced attribute from the element's underlying DOM node.
9879 * @param {String} namespace The namespace in which to look for the attribute
9880 * @param {String} name The attribute name
9881 * @return {String} The attribute value
9883 getAttributeNS : Roo.isIE ? function(ns, name){
9885 var type = typeof d[ns+":"+name];
9886 if(type != 'undefined' && type != 'unknown'){
9887 return d[ns+":"+name];
9890 } : function(ns, name){
9892 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9897 * Sets or Returns the value the dom attribute value
9898 * @param {String|Object} name The attribute name (or object to set multiple attributes)
9899 * @param {String} value (optional) The value to set the attribute to
9900 * @return {String} The attribute value
9902 attr : function(name){
9903 if (arguments.length > 1) {
9904 this.dom.setAttribute(name, arguments[1]);
9905 return arguments[1];
9907 if (typeof(name) == 'object') {
9908 for(var i in name) {
9909 this.attr(i, name[i]);
9915 if (!this.dom.hasAttribute(name)) {
9918 return this.dom.getAttribute(name);
9925 var ep = El.prototype;
9928 * Appends an event handler (Shorthand for addListener)
9929 * @param {String} eventName The type of event to append
9930 * @param {Function} fn The method the event invokes
9931 * @param {Object} scope (optional) The scope (this object) of the fn
9932 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9935 ep.on = ep.addListener;
9937 ep.mon = ep.addListener;
9940 * Removes an event handler from this element (shorthand for removeListener)
9941 * @param {String} eventName the type of event to remove
9942 * @param {Function} fn the method the event invokes
9943 * @return {Roo.Element} this
9946 ep.un = ep.removeListener;
9949 * true to automatically adjust width and height settings for box-model issues (default to true)
9951 ep.autoBoxAdjust = true;
9954 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9957 El.addUnits = function(v, defaultUnit){
9958 if(v === "" || v == "auto"){
9961 if(v === undefined){
9964 if(typeof v == "number" || !El.unitPattern.test(v)){
9965 return v + (defaultUnit || 'px');
9970 // special markup used throughout Roo when box wrapping elements
9971 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>';
9973 * Visibility mode constant - Use visibility to hide element
9979 * Visibility mode constant - Use display to hide element
9985 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9986 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9987 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9999 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
10000 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
10001 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
10002 * @return {Element} The Element object
10005 El.get = function(el){
10007 if(!el){ return null; }
10008 if(typeof el == "string"){ // element id
10009 if(!(elm = document.getElementById(el))){
10012 if(ex = El.cache[el]){
10015 ex = El.cache[el] = new El(elm);
10018 }else if(el.tagName){ // dom element
10022 if(ex = El.cache[id]){
10025 ex = El.cache[id] = new El(el);
10028 }else if(el instanceof El){
10030 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
10031 // catch case where it hasn't been appended
10032 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
10035 }else if(el.isComposite){
10037 }else if(el instanceof Array){
10038 return El.select(el);
10039 }else if(el == document){
10040 // create a bogus element object representing the document object
10042 var f = function(){};
10043 f.prototype = El.prototype;
10045 docEl.dom = document;
10053 El.uncache = function(el){
10054 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
10056 delete El.cache[a[i].id || a[i]];
10062 // Garbage collection - uncache elements/purge listeners on orphaned elements
10063 // so we don't hold a reference and cause the browser to retain them
10064 El.garbageCollect = function(){
10065 if(!Roo.enableGarbageCollector){
10066 clearInterval(El.collectorThread);
10069 for(var eid in El.cache){
10070 var el = El.cache[eid], d = el.dom;
10071 // -------------------------------------------------------
10072 // Determining what is garbage:
10073 // -------------------------------------------------------
10075 // dom node is null, definitely garbage
10076 // -------------------------------------------------------
10078 // no parentNode == direct orphan, definitely garbage
10079 // -------------------------------------------------------
10080 // !d.offsetParent && !document.getElementById(eid)
10081 // display none elements have no offsetParent so we will
10082 // also try to look it up by it's id. However, check
10083 // offsetParent first so we don't do unneeded lookups.
10084 // This enables collection of elements that are not orphans
10085 // directly, but somewhere up the line they have an orphan
10087 // -------------------------------------------------------
10088 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
10089 delete El.cache[eid];
10090 if(d && Roo.enableListenerCollection){
10096 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
10100 El.Flyweight = function(dom){
10103 El.Flyweight.prototype = El.prototype;
10105 El._flyweights = {};
10107 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
10108 * the dom node can be overwritten by other code.
10109 * @param {String/HTMLElement} el The dom node or id
10110 * @param {String} named (optional) Allows for creation of named reusable flyweights to
10111 * prevent conflicts (e.g. internally Roo uses "_internal")
10113 * @return {Element} The shared Element object
10115 El.fly = function(el, named){
10116 named = named || '_global';
10117 el = Roo.getDom(el);
10121 if(!El._flyweights[named]){
10122 El._flyweights[named] = new El.Flyweight();
10124 El._flyweights[named].dom = el;
10125 return El._flyweights[named];
10129 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
10130 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
10131 * Shorthand of {@link Roo.Element#get}
10132 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
10133 * @return {Element} The Element object
10139 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
10140 * the dom node can be overwritten by other code.
10141 * Shorthand of {@link Roo.Element#fly}
10142 * @param {String/HTMLElement} el The dom node or id
10143 * @param {String} named (optional) Allows for creation of named reusable flyweights to
10144 * prevent conflicts (e.g. internally Roo uses "_internal")
10146 * @return {Element} The shared Element object
10152 // speedy lookup for elements never to box adjust
10153 var noBoxAdjust = Roo.isStrict ? {
10156 input:1, select:1, textarea:1
10158 if(Roo.isIE || Roo.isGecko){
10159 noBoxAdjust['button'] = 1;
10163 Roo.EventManager.on(window, 'unload', function(){
10165 delete El._flyweights;
10173 Roo.Element.selectorFunction = Roo.DomQuery.select;
10176 Roo.Element.select = function(selector, unique, root){
10178 if(typeof selector == "string"){
10179 els = Roo.Element.selectorFunction(selector, root);
10180 }else if(selector.length !== undefined){
10183 throw "Invalid selector";
10185 if(unique === true){
10186 return new Roo.CompositeElement(els);
10188 return new Roo.CompositeElementLite(els);
10192 * Selects elements based on the passed CSS selector to enable working on them as 1.
10193 * @param {String/Array} selector The CSS selector or an array of elements
10194 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
10195 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
10196 * @return {CompositeElementLite/CompositeElement}
10200 Roo.select = Roo.Element.select;
10217 * Ext JS Library 1.1.1
10218 * Copyright(c) 2006-2007, Ext JS, LLC.
10220 * Originally Released Under LGPL - original licence link has changed is not relivant.
10223 * <script type="text/javascript">
10228 //Notifies Element that fx methods are available
10229 Roo.enableFx = true;
10233 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
10234 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
10235 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
10236 * Element effects to work.</p><br/>
10238 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
10239 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
10240 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
10241 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
10242 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
10243 * expected results and should be done with care.</p><br/>
10245 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
10246 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
10249 ----- -----------------------------
10250 tl The top left corner
10251 t The center of the top edge
10252 tr The top right corner
10253 l The center of the left edge
10254 r The center of the right edge
10255 bl The bottom left corner
10256 b The center of the bottom edge
10257 br The bottom right corner
10259 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
10260 * below are common options that can be passed to any Fx method.</b>
10261 * @cfg {Function} callback A function called when the effect is finished
10262 * @cfg {Object} scope The scope of the effect function
10263 * @cfg {String} easing A valid Easing value for the effect
10264 * @cfg {String} afterCls A css class to apply after the effect
10265 * @cfg {Number} duration The length of time (in seconds) that the effect should last
10266 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
10267 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
10268 * effects that end with the element being visually hidden, ignored otherwise)
10269 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
10270 * a function which returns such a specification that will be applied to the Element after the effect finishes
10271 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
10272 * @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
10273 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
10277 * Slides the element into view. An anchor point can be optionally passed to set the point of
10278 * origin for the slide effect. This function automatically handles wrapping the element with
10279 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10282 // default: slide the element in from the top
10285 // custom: slide the element in from the right with a 2-second duration
10286 el.slideIn('r', { duration: 2 });
10288 // common config options shown with default values
10294 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10295 * @param {Object} options (optional) Object literal with any of the Fx config options
10296 * @return {Roo.Element} The Element
10298 slideIn : function(anchor, o){
10299 var el = this.getFxEl();
10302 el.queueFx(o, function(){
10304 anchor = anchor || "t";
10306 // fix display to visibility
10309 // restore values after effect
10310 var r = this.getFxRestore();
10311 var b = this.getBox();
10312 // fixed size for slide
10316 var wrap = this.fxWrap(r.pos, o, "hidden");
10318 var st = this.dom.style;
10319 st.visibility = "visible";
10320 st.position = "absolute";
10322 // clear out temp styles after slide and unwrap
10323 var after = function(){
10324 el.fxUnwrap(wrap, r.pos, o);
10325 st.width = r.width;
10326 st.height = r.height;
10329 // time to calc the positions
10330 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10332 switch(anchor.toLowerCase()){
10334 wrap.setSize(b.width, 0);
10335 st.left = st.bottom = "0";
10339 wrap.setSize(0, b.height);
10340 st.right = st.top = "0";
10344 wrap.setSize(0, b.height);
10345 wrap.setX(b.right);
10346 st.left = st.top = "0";
10347 a = {width: bw, points: pt};
10350 wrap.setSize(b.width, 0);
10351 wrap.setY(b.bottom);
10352 st.left = st.top = "0";
10353 a = {height: bh, points: pt};
10356 wrap.setSize(0, 0);
10357 st.right = st.bottom = "0";
10358 a = {width: bw, height: bh};
10361 wrap.setSize(0, 0);
10362 wrap.setY(b.y+b.height);
10363 st.right = st.top = "0";
10364 a = {width: bw, height: bh, points: pt};
10367 wrap.setSize(0, 0);
10368 wrap.setXY([b.right, b.bottom]);
10369 st.left = st.top = "0";
10370 a = {width: bw, height: bh, points: pt};
10373 wrap.setSize(0, 0);
10374 wrap.setX(b.x+b.width);
10375 st.left = st.bottom = "0";
10376 a = {width: bw, height: bh, points: pt};
10379 this.dom.style.visibility = "visible";
10382 arguments.callee.anim = wrap.fxanim(a,
10392 * Slides the element out of view. An anchor point can be optionally passed to set the end point
10393 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
10394 * 'hidden') but block elements will still take up space in the document. The element must be removed
10395 * from the DOM using the 'remove' config option if desired. This function automatically handles
10396 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10399 // default: slide the element out to the top
10402 // custom: slide the element out to the right with a 2-second duration
10403 el.slideOut('r', { duration: 2 });
10405 // common config options shown with default values
10413 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10414 * @param {Object} options (optional) Object literal with any of the Fx config options
10415 * @return {Roo.Element} The Element
10417 slideOut : function(anchor, o){
10418 var el = this.getFxEl();
10421 el.queueFx(o, function(){
10423 anchor = anchor || "t";
10425 // restore values after effect
10426 var r = this.getFxRestore();
10428 var b = this.getBox();
10429 // fixed size for slide
10433 var wrap = this.fxWrap(r.pos, o, "visible");
10435 var st = this.dom.style;
10436 st.visibility = "visible";
10437 st.position = "absolute";
10441 var after = function(){
10443 el.setDisplayed(false);
10448 el.fxUnwrap(wrap, r.pos, o);
10450 st.width = r.width;
10451 st.height = r.height;
10456 var a, zero = {to: 0};
10457 switch(anchor.toLowerCase()){
10459 st.left = st.bottom = "0";
10460 a = {height: zero};
10463 st.right = st.top = "0";
10467 st.left = st.top = "0";
10468 a = {width: zero, points: {to:[b.right, b.y]}};
10471 st.left = st.top = "0";
10472 a = {height: zero, points: {to:[b.x, b.bottom]}};
10475 st.right = st.bottom = "0";
10476 a = {width: zero, height: zero};
10479 st.right = st.top = "0";
10480 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10483 st.left = st.top = "0";
10484 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10487 st.left = st.bottom = "0";
10488 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10492 arguments.callee.anim = wrap.fxanim(a,
10502 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
10503 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
10504 * The element must be removed from the DOM using the 'remove' config option if desired.
10510 // common config options shown with default values
10518 * @param {Object} options (optional) Object literal with any of the Fx config options
10519 * @return {Roo.Element} The Element
10521 puff : function(o){
10522 var el = this.getFxEl();
10525 el.queueFx(o, function(){
10526 this.clearOpacity();
10529 // restore values after effect
10530 var r = this.getFxRestore();
10531 var st = this.dom.style;
10533 var after = function(){
10535 el.setDisplayed(false);
10542 el.setPositioning(r.pos);
10543 st.width = r.width;
10544 st.height = r.height;
10549 var width = this.getWidth();
10550 var height = this.getHeight();
10552 arguments.callee.anim = this.fxanim({
10553 width : {to: this.adjustWidth(width * 2)},
10554 height : {to: this.adjustHeight(height * 2)},
10555 points : {by: [-(width * .5), -(height * .5)]},
10557 fontSize: {to:200, unit: "%"}
10568 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10569 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
10570 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10576 // all config options shown with default values
10584 * @param {Object} options (optional) Object literal with any of the Fx config options
10585 * @return {Roo.Element} The Element
10587 switchOff : function(o){
10588 var el = this.getFxEl();
10591 el.queueFx(o, function(){
10592 this.clearOpacity();
10595 // restore values after effect
10596 var r = this.getFxRestore();
10597 var st = this.dom.style;
10599 var after = function(){
10601 el.setDisplayed(false);
10607 el.setPositioning(r.pos);
10608 st.width = r.width;
10609 st.height = r.height;
10614 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10615 this.clearOpacity();
10619 points:{by:[0, this.getHeight() * .5]}
10620 }, o, 'motion', 0.3, 'easeIn', after);
10621 }).defer(100, this);
10628 * Highlights the Element by setting a color (applies to the background-color by default, but can be
10629 * changed using the "attr" config option) and then fading back to the original color. If no original
10630 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10633 // default: highlight background to yellow
10636 // custom: highlight foreground text to blue for 2 seconds
10637 el.highlight("0000ff", { attr: 'color', duration: 2 });
10639 // common config options shown with default values
10640 el.highlight("ffff9c", {
10641 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10642 endColor: (current color) or "ffffff",
10647 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10648 * @param {Object} options (optional) Object literal with any of the Fx config options
10649 * @return {Roo.Element} The Element
10651 highlight : function(color, o){
10652 var el = this.getFxEl();
10655 el.queueFx(o, function(){
10656 color = color || "ffff9c";
10657 attr = o.attr || "backgroundColor";
10659 this.clearOpacity();
10662 var origColor = this.getColor(attr);
10663 var restoreColor = this.dom.style[attr];
10664 endColor = (o.endColor || origColor) || "ffffff";
10666 var after = function(){
10667 el.dom.style[attr] = restoreColor;
10672 a[attr] = {from: color, to: endColor};
10673 arguments.callee.anim = this.fxanim(a,
10683 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10686 // default: a single light blue ripple
10689 // custom: 3 red ripples lasting 3 seconds total
10690 el.frame("ff0000", 3, { duration: 3 });
10692 // common config options shown with default values
10693 el.frame("C3DAF9", 1, {
10694 duration: 1 //duration of entire animation (not each individual ripple)
10695 // Note: Easing is not configurable and will be ignored if included
10698 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10699 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10700 * @param {Object} options (optional) Object literal with any of the Fx config options
10701 * @return {Roo.Element} The Element
10703 frame : function(color, count, o){
10704 var el = this.getFxEl();
10707 el.queueFx(o, function(){
10708 color = color || "#C3DAF9";
10709 if(color.length == 6){
10710 color = "#" + color;
10712 count = count || 1;
10713 duration = o.duration || 1;
10716 var b = this.getBox();
10717 var animFn = function(){
10718 var proxy = this.createProxy({
10721 visbility:"hidden",
10722 position:"absolute",
10723 "z-index":"35000", // yee haw
10724 border:"0px solid " + color
10727 var scale = Roo.isBorderBox ? 2 : 1;
10729 top:{from:b.y, to:b.y - 20},
10730 left:{from:b.x, to:b.x - 20},
10731 borderWidth:{from:0, to:10},
10732 opacity:{from:1, to:0},
10733 height:{from:b.height, to:(b.height + (20*scale))},
10734 width:{from:b.width, to:(b.width + (20*scale))}
10735 }, duration, function(){
10739 animFn.defer((duration/2)*1000, this);
10750 * Creates a pause before any subsequent queued effects begin. If there are
10751 * no effects queued after the pause it will have no effect.
10756 * @param {Number} seconds The length of time to pause (in seconds)
10757 * @return {Roo.Element} The Element
10759 pause : function(seconds){
10760 var el = this.getFxEl();
10763 el.queueFx(o, function(){
10764 setTimeout(function(){
10766 }, seconds * 1000);
10772 * Fade an element in (from transparent to opaque). The ending opacity can be specified
10773 * using the "endOpacity" config option.
10776 // default: fade in from opacity 0 to 100%
10779 // custom: fade in from opacity 0 to 75% over 2 seconds
10780 el.fadeIn({ endOpacity: .75, duration: 2});
10782 // common config options shown with default values
10784 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10789 * @param {Object} options (optional) Object literal with any of the Fx config options
10790 * @return {Roo.Element} The Element
10792 fadeIn : function(o){
10793 var el = this.getFxEl();
10795 el.queueFx(o, function(){
10796 this.setOpacity(0);
10798 this.dom.style.visibility = 'visible';
10799 var to = o.endOpacity || 1;
10800 arguments.callee.anim = this.fxanim({opacity:{to:to}},
10801 o, null, .5, "easeOut", function(){
10803 this.clearOpacity();
10812 * Fade an element out (from opaque to transparent). The ending opacity can be specified
10813 * using the "endOpacity" config option.
10816 // default: fade out from the element's current opacity to 0
10819 // custom: fade out from the element's current opacity to 25% over 2 seconds
10820 el.fadeOut({ endOpacity: .25, duration: 2});
10822 // common config options shown with default values
10824 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10831 * @param {Object} options (optional) Object literal with any of the Fx config options
10832 * @return {Roo.Element} The Element
10834 fadeOut : function(o){
10835 var el = this.getFxEl();
10837 el.queueFx(o, function(){
10838 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10839 o, null, .5, "easeOut", function(){
10840 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10841 this.dom.style.display = "none";
10843 this.dom.style.visibility = "hidden";
10845 this.clearOpacity();
10853 * Animates the transition of an element's dimensions from a starting height/width
10854 * to an ending height/width.
10857 // change height and width to 100x100 pixels
10858 el.scale(100, 100);
10860 // common config options shown with default values. The height and width will default to
10861 // the element's existing values if passed as null.
10864 [element's height], {
10869 * @param {Number} width The new width (pass undefined to keep the original width)
10870 * @param {Number} height The new height (pass undefined to keep the original height)
10871 * @param {Object} options (optional) Object literal with any of the Fx config options
10872 * @return {Roo.Element} The Element
10874 scale : function(w, h, o){
10875 this.shift(Roo.apply({}, o, {
10883 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10884 * Any of these properties not specified in the config object will not be changed. This effect
10885 * requires that at least one new dimension, position or opacity setting must be passed in on
10886 * the config object in order for the function to have any effect.
10889 // slide the element horizontally to x position 200 while changing the height and opacity
10890 el.shift({ x: 200, height: 50, opacity: .8 });
10892 // common config options shown with default values.
10894 width: [element's width],
10895 height: [element's height],
10896 x: [element's x position],
10897 y: [element's y position],
10898 opacity: [element's opacity],
10903 * @param {Object} options Object literal with any of the Fx config options
10904 * @return {Roo.Element} The Element
10906 shift : function(o){
10907 var el = this.getFxEl();
10909 el.queueFx(o, function(){
10910 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
10911 if(w !== undefined){
10912 a.width = {to: this.adjustWidth(w)};
10914 if(h !== undefined){
10915 a.height = {to: this.adjustHeight(h)};
10917 if(x !== undefined || y !== undefined){
10919 x !== undefined ? x : this.getX(),
10920 y !== undefined ? y : this.getY()
10923 if(op !== undefined){
10924 a.opacity = {to: op};
10926 if(o.xy !== undefined){
10927 a.points = {to: o.xy};
10929 arguments.callee.anim = this.fxanim(a,
10930 o, 'motion', .35, "easeOut", function(){
10938 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
10939 * ending point of the effect.
10942 // default: slide the element downward while fading out
10945 // custom: slide the element out to the right with a 2-second duration
10946 el.ghost('r', { duration: 2 });
10948 // common config options shown with default values
10956 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10957 * @param {Object} options (optional) Object literal with any of the Fx config options
10958 * @return {Roo.Element} The Element
10960 ghost : function(anchor, o){
10961 var el = this.getFxEl();
10964 el.queueFx(o, function(){
10965 anchor = anchor || "b";
10967 // restore values after effect
10968 var r = this.getFxRestore();
10969 var w = this.getWidth(),
10970 h = this.getHeight();
10972 var st = this.dom.style;
10974 var after = function(){
10976 el.setDisplayed(false);
10982 el.setPositioning(r.pos);
10983 st.width = r.width;
10984 st.height = r.height;
10989 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10990 switch(anchor.toLowerCase()){
11017 arguments.callee.anim = this.fxanim(a,
11027 * Ensures that all effects queued after syncFx is called on the element are
11028 * run concurrently. This is the opposite of {@link #sequenceFx}.
11029 * @return {Roo.Element} The Element
11031 syncFx : function(){
11032 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
11041 * Ensures that all effects queued after sequenceFx is called on the element are
11042 * run in sequence. This is the opposite of {@link #syncFx}.
11043 * @return {Roo.Element} The Element
11045 sequenceFx : function(){
11046 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
11048 concurrent : false,
11055 nextFx : function(){
11056 var ef = this.fxQueue[0];
11063 * Returns true if the element has any effects actively running or queued, else returns false.
11064 * @return {Boolean} True if element has active effects, else false
11066 hasActiveFx : function(){
11067 return this.fxQueue && this.fxQueue[0];
11071 * Stops any running effects and clears the element's internal effects queue if it contains
11072 * any additional effects that haven't started yet.
11073 * @return {Roo.Element} The Element
11075 stopFx : function(){
11076 if(this.hasActiveFx()){
11077 var cur = this.fxQueue[0];
11078 if(cur && cur.anim && cur.anim.isAnimated()){
11079 this.fxQueue = [cur]; // clear out others
11080 cur.anim.stop(true);
11087 beforeFx : function(o){
11088 if(this.hasActiveFx() && !o.concurrent){
11099 * Returns true if the element is currently blocking so that no other effect can be queued
11100 * until this effect is finished, else returns false if blocking is not set. This is commonly
11101 * used to ensure that an effect initiated by a user action runs to completion prior to the
11102 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
11103 * @return {Boolean} True if blocking, else false
11105 hasFxBlock : function(){
11106 var q = this.fxQueue;
11107 return q && q[0] && q[0].block;
11111 queueFx : function(o, fn){
11115 if(!this.hasFxBlock()){
11116 Roo.applyIf(o, this.fxDefaults);
11118 var run = this.beforeFx(o);
11119 fn.block = o.block;
11120 this.fxQueue.push(fn);
11132 fxWrap : function(pos, o, vis){
11134 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
11137 wrapXY = this.getXY();
11139 var div = document.createElement("div");
11140 div.style.visibility = vis;
11141 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
11142 wrap.setPositioning(pos);
11143 if(wrap.getStyle("position") == "static"){
11144 wrap.position("relative");
11146 this.clearPositioning('auto');
11148 wrap.dom.appendChild(this.dom);
11150 wrap.setXY(wrapXY);
11157 fxUnwrap : function(wrap, pos, o){
11158 this.clearPositioning();
11159 this.setPositioning(pos);
11161 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
11167 getFxRestore : function(){
11168 var st = this.dom.style;
11169 return {pos: this.getPositioning(), width: st.width, height : st.height};
11173 afterFx : function(o){
11175 this.applyStyles(o.afterStyle);
11178 this.addClass(o.afterCls);
11180 if(o.remove === true){
11183 Roo.callback(o.callback, o.scope, [this]);
11185 this.fxQueue.shift();
11191 getFxEl : function(){ // support for composite element fx
11192 return Roo.get(this.dom);
11196 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
11197 animType = animType || 'run';
11199 var anim = Roo.lib.Anim[animType](
11201 (opt.duration || defaultDur) || .35,
11202 (opt.easing || defaultEase) || 'easeOut',
11204 Roo.callback(cb, this);
11213 // backwords compat
11214 Roo.Fx.resize = Roo.Fx.scale;
11216 //When included, Roo.Fx is automatically applied to Element so that all basic
11217 //effects are available directly via the Element API
11218 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
11220 * Ext JS Library 1.1.1
11221 * Copyright(c) 2006-2007, Ext JS, LLC.
11223 * Originally Released Under LGPL - original licence link has changed is not relivant.
11226 * <script type="text/javascript">
11231 * @class Roo.CompositeElement
11232 * Standard composite class. Creates a Roo.Element for every element in the collection.
11234 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11235 * actions will be performed on all the elements in this collection.</b>
11237 * All methods return <i>this</i> and can be chained.
11239 var els = Roo.select("#some-el div.some-class", true);
11240 // or select directly from an existing element
11241 var el = Roo.get('some-el');
11242 el.select('div.some-class', true);
11244 els.setWidth(100); // all elements become 100 width
11245 els.hide(true); // all elements fade out and hide
11247 els.setWidth(100).hide(true);
11250 Roo.CompositeElement = function(els){
11251 this.elements = [];
11252 this.addElements(els);
11254 Roo.CompositeElement.prototype = {
11256 addElements : function(els){
11260 if(typeof els == "string"){
11261 els = Roo.Element.selectorFunction(els);
11263 var yels = this.elements;
11264 var index = yels.length-1;
11265 for(var i = 0, len = els.length; i < len; i++) {
11266 yels[++index] = Roo.get(els[i]);
11272 * Clears this composite and adds the elements returned by the passed selector.
11273 * @param {String/Array} els A string CSS selector, an array of elements or an element
11274 * @return {CompositeElement} this
11276 fill : function(els){
11277 this.elements = [];
11283 * Filters this composite to only elements that match the passed selector.
11284 * @param {String} selector A string CSS selector
11285 * @param {Boolean} inverse return inverse filter (not matches)
11286 * @return {CompositeElement} this
11288 filter : function(selector, inverse){
11290 inverse = inverse || false;
11291 this.each(function(el){
11292 var match = inverse ? !el.is(selector) : el.is(selector);
11294 els[els.length] = el.dom;
11301 invoke : function(fn, args){
11302 var els = this.elements;
11303 for(var i = 0, len = els.length; i < len; i++) {
11304 Roo.Element.prototype[fn].apply(els[i], args);
11309 * Adds elements to this composite.
11310 * @param {String/Array} els A string CSS selector, an array of elements or an element
11311 * @return {CompositeElement} this
11313 add : function(els){
11314 if(typeof els == "string"){
11315 this.addElements(Roo.Element.selectorFunction(els));
11316 }else if(els.length !== undefined){
11317 this.addElements(els);
11319 this.addElements([els]);
11324 * Calls the passed function passing (el, this, index) for each element in this composite.
11325 * @param {Function} fn The function to call
11326 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11327 * @return {CompositeElement} this
11329 each : function(fn, scope){
11330 var els = this.elements;
11331 for(var i = 0, len = els.length; i < len; i++){
11332 if(fn.call(scope || els[i], els[i], this, i) === false) {
11340 * Returns the Element object at the specified index
11341 * @param {Number} index
11342 * @return {Roo.Element}
11344 item : function(index){
11345 return this.elements[index] || null;
11349 * Returns the first Element
11350 * @return {Roo.Element}
11352 first : function(){
11353 return this.item(0);
11357 * Returns the last Element
11358 * @return {Roo.Element}
11361 return this.item(this.elements.length-1);
11365 * Returns the number of elements in this composite
11368 getCount : function(){
11369 return this.elements.length;
11373 * Returns true if this composite contains the passed element
11376 contains : function(el){
11377 return this.indexOf(el) !== -1;
11381 * Returns true if this composite contains the passed element
11384 indexOf : function(el){
11385 return this.elements.indexOf(Roo.get(el));
11390 * Removes the specified element(s).
11391 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11392 * or an array of any of those.
11393 * @param {Boolean} removeDom (optional) True to also remove the element from the document
11394 * @return {CompositeElement} this
11396 removeElement : function(el, removeDom){
11397 if(el instanceof Array){
11398 for(var i = 0, len = el.length; i < len; i++){
11399 this.removeElement(el[i]);
11403 var index = typeof el == 'number' ? el : this.indexOf(el);
11406 var d = this.elements[index];
11410 d.parentNode.removeChild(d);
11413 this.elements.splice(index, 1);
11419 * Replaces the specified element with the passed element.
11420 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11422 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11423 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11424 * @return {CompositeElement} this
11426 replaceElement : function(el, replacement, domReplace){
11427 var index = typeof el == 'number' ? el : this.indexOf(el);
11430 this.elements[index].replaceWith(replacement);
11432 this.elements.splice(index, 1, Roo.get(replacement))
11439 * Removes all elements.
11441 clear : function(){
11442 this.elements = [];
11446 Roo.CompositeElement.createCall = function(proto, fnName){
11447 if(!proto[fnName]){
11448 proto[fnName] = function(){
11449 return this.invoke(fnName, arguments);
11453 for(var fnName in Roo.Element.prototype){
11454 if(typeof Roo.Element.prototype[fnName] == "function"){
11455 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11461 * Ext JS Library 1.1.1
11462 * Copyright(c) 2006-2007, Ext JS, LLC.
11464 * Originally Released Under LGPL - original licence link has changed is not relivant.
11467 * <script type="text/javascript">
11471 * @class Roo.CompositeElementLite
11472 * @extends Roo.CompositeElement
11473 * Flyweight composite class. Reuses the same Roo.Element for element operations.
11475 var els = Roo.select("#some-el div.some-class");
11476 // or select directly from an existing element
11477 var el = Roo.get('some-el');
11478 el.select('div.some-class');
11480 els.setWidth(100); // all elements become 100 width
11481 els.hide(true); // all elements fade out and hide
11483 els.setWidth(100).hide(true);
11484 </code></pre><br><br>
11485 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11486 * actions will be performed on all the elements in this collection.</b>
11488 Roo.CompositeElementLite = function(els){
11489 Roo.CompositeElementLite.superclass.constructor.call(this, els);
11490 this.el = new Roo.Element.Flyweight();
11492 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11493 addElements : function(els){
11495 if(els instanceof Array){
11496 this.elements = this.elements.concat(els);
11498 var yels = this.elements;
11499 var index = yels.length-1;
11500 for(var i = 0, len = els.length; i < len; i++) {
11501 yels[++index] = els[i];
11507 invoke : function(fn, args){
11508 var els = this.elements;
11510 for(var i = 0, len = els.length; i < len; i++) {
11512 Roo.Element.prototype[fn].apply(el, args);
11517 * Returns a flyweight Element of the dom element object at the specified index
11518 * @param {Number} index
11519 * @return {Roo.Element}
11521 item : function(index){
11522 if(!this.elements[index]){
11525 this.el.dom = this.elements[index];
11529 // fixes scope with flyweight
11530 addListener : function(eventName, handler, scope, opt){
11531 var els = this.elements;
11532 for(var i = 0, len = els.length; i < len; i++) {
11533 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11539 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11540 * passed is the flyweight (shared) Roo.Element instance, so if you require a
11541 * a reference to the dom node, use el.dom.</b>
11542 * @param {Function} fn The function to call
11543 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11544 * @return {CompositeElement} this
11546 each : function(fn, scope){
11547 var els = this.elements;
11549 for(var i = 0, len = els.length; i < len; i++){
11551 if(fn.call(scope || el, el, this, i) === false){
11558 indexOf : function(el){
11559 return this.elements.indexOf(Roo.getDom(el));
11562 replaceElement : function(el, replacement, domReplace){
11563 var index = typeof el == 'number' ? el : this.indexOf(el);
11565 replacement = Roo.getDom(replacement);
11567 var d = this.elements[index];
11568 d.parentNode.insertBefore(replacement, d);
11569 d.parentNode.removeChild(d);
11571 this.elements.splice(index, 1, replacement);
11576 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11580 * Ext JS Library 1.1.1
11581 * Copyright(c) 2006-2007, Ext JS, LLC.
11583 * Originally Released Under LGPL - original licence link has changed is not relivant.
11586 * <script type="text/javascript">
11592 * @class Roo.data.Connection
11593 * @extends Roo.util.Observable
11594 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11595 * either to a configured URL, or to a URL specified at request time.
11597 * Requests made by this class are asynchronous, and will return immediately. No data from
11598 * the server will be available to the statement immediately following the {@link #request} call.
11599 * To process returned data, use a callback in the request options object, or an event listener.
11601 * Note: If you are doing a file upload, you will not get a normal response object sent back to
11602 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11603 * The response object is created using the innerHTML of the IFRAME's document as the responseText
11604 * property and, if present, the IFRAME's XML document as the responseXML property.
11606 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11607 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
11608 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11609 * standard DOM methods.
11611 * @param {Object} config a configuration object.
11613 Roo.data.Connection = function(config){
11614 Roo.apply(this, config);
11617 * @event beforerequest
11618 * Fires before a network request is made to retrieve a data object.
11619 * @param {Connection} conn This Connection object.
11620 * @param {Object} options The options config object passed to the {@link #request} method.
11622 "beforerequest" : true,
11624 * @event requestcomplete
11625 * Fires if the request was successfully completed.
11626 * @param {Connection} conn This Connection object.
11627 * @param {Object} response The XHR object containing the response data.
11628 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11629 * @param {Object} options The options config object passed to the {@link #request} method.
11631 "requestcomplete" : true,
11633 * @event requestexception
11634 * Fires if an error HTTP status was returned from the server.
11635 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11636 * @param {Connection} conn This Connection object.
11637 * @param {Object} response The XHR object containing the response data.
11638 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11639 * @param {Object} options The options config object passed to the {@link #request} method.
11641 "requestexception" : true
11643 Roo.data.Connection.superclass.constructor.call(this);
11646 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11648 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11651 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11652 * extra parameters to each request made by this object. (defaults to undefined)
11655 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11656 * to each request made by this object. (defaults to undefined)
11659 * @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)
11662 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11666 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11672 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11675 disableCaching: true,
11678 * Sends an HTTP request to a remote server.
11679 * @param {Object} options An object which may contain the following properties:<ul>
11680 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11681 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11682 * request, a url encoded string or a function to call to get either.</li>
11683 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11684 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11685 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11686 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11687 * <li>options {Object} The parameter to the request call.</li>
11688 * <li>success {Boolean} True if the request succeeded.</li>
11689 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11691 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11692 * The callback is passed the following parameters:<ul>
11693 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11694 * <li>options {Object} The parameter to the request call.</li>
11696 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11697 * The callback is passed the following parameters:<ul>
11698 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11699 * <li>options {Object} The parameter to the request call.</li>
11701 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11702 * for the callback function. Defaults to the browser window.</li>
11703 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11704 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11705 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11706 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11707 * params for the post data. Any params will be appended to the URL.</li>
11708 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11710 * @return {Number} transactionId
11712 request : function(o){
11713 if(this.fireEvent("beforerequest", this, o) !== false){
11716 if(typeof p == "function"){
11717 p = p.call(o.scope||window, o);
11719 if(typeof p == "object"){
11720 p = Roo.urlEncode(o.params);
11722 if(this.extraParams){
11723 var extras = Roo.urlEncode(this.extraParams);
11724 p = p ? (p + '&' + extras) : extras;
11727 var url = o.url || this.url;
11728 if(typeof url == 'function'){
11729 url = url.call(o.scope||window, o);
11733 var form = Roo.getDom(o.form);
11734 url = url || form.action;
11736 var enctype = form.getAttribute("enctype");
11739 return this.doFormDataUpload(o, url);
11742 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11743 return this.doFormUpload(o, p, url);
11745 var f = Roo.lib.Ajax.serializeForm(form);
11746 p = p ? (p + '&' + f) : f;
11749 if (!o.form && o.formData) {
11750 o.formData = o.formData === true ? new FormData() : o.formData;
11751 for (var k in o.params) {
11752 o.formData.append(k,o.params[k]);
11755 return this.doFormDataUpload(o, url);
11759 var hs = o.headers;
11760 if(this.defaultHeaders){
11761 hs = Roo.apply(hs || {}, this.defaultHeaders);
11768 success: this.handleResponse,
11769 failure: this.handleFailure,
11771 argument: {options: o},
11772 timeout : o.timeout || this.timeout
11775 var method = o.method||this.method||(p ? "POST" : "GET");
11777 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11778 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11781 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11785 }else if(this.autoAbort !== false){
11789 if((method == 'GET' && p) || o.xmlData){
11790 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11793 Roo.lib.Ajax.useDefaultHeader = typeof(o.headers) == 'undefined' || typeof(o.headers['Content-Type']) == 'undefined';
11794 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11795 Roo.lib.Ajax.useDefaultHeader == true;
11796 return this.transId;
11798 Roo.callback(o.callback, o.scope, [o, null, null]);
11804 * Determine whether this object has a request outstanding.
11805 * @param {Number} transactionId (Optional) defaults to the last transaction
11806 * @return {Boolean} True if there is an outstanding request.
11808 isLoading : function(transId){
11810 return Roo.lib.Ajax.isCallInProgress(transId);
11812 return this.transId ? true : false;
11817 * Aborts any outstanding request.
11818 * @param {Number} transactionId (Optional) defaults to the last transaction
11820 abort : function(transId){
11821 if(transId || this.isLoading()){
11822 Roo.lib.Ajax.abort(transId || this.transId);
11827 handleResponse : function(response){
11828 this.transId = false;
11829 var options = response.argument.options;
11830 response.argument = options ? options.argument : null;
11831 this.fireEvent("requestcomplete", this, response, options);
11832 Roo.callback(options.success, options.scope, [response, options]);
11833 Roo.callback(options.callback, options.scope, [options, true, response]);
11837 handleFailure : function(response, e){
11838 this.transId = false;
11839 var options = response.argument.options;
11840 response.argument = options ? options.argument : null;
11841 this.fireEvent("requestexception", this, response, options, e);
11842 Roo.callback(options.failure, options.scope, [response, options]);
11843 Roo.callback(options.callback, options.scope, [options, false, response]);
11847 doFormUpload : function(o, ps, url){
11849 var frame = document.createElement('iframe');
11852 frame.className = 'x-hidden';
11854 frame.src = Roo.SSL_SECURE_URL;
11856 document.body.appendChild(frame);
11859 document.frames[id].name = id;
11862 var form = Roo.getDom(o.form);
11864 form.method = 'POST';
11865 form.enctype = form.encoding = 'multipart/form-data';
11871 if(ps){ // add dynamic params
11873 ps = Roo.urlDecode(ps, false);
11875 if(ps.hasOwnProperty(k)){
11876 hd = document.createElement('input');
11877 hd.type = 'hidden';
11880 form.appendChild(hd);
11887 var r = { // bogus response object
11892 r.argument = o ? o.argument : null;
11897 doc = frame.contentWindow.document;
11899 doc = (frame.contentDocument || window.frames[id].document);
11901 if(doc && doc.body){
11902 r.responseText = doc.body.innerHTML;
11904 if(doc && doc.XMLDocument){
11905 r.responseXML = doc.XMLDocument;
11907 r.responseXML = doc;
11914 Roo.EventManager.removeListener(frame, 'load', cb, this);
11916 this.fireEvent("requestcomplete", this, r, o);
11917 Roo.callback(o.success, o.scope, [r, o]);
11918 Roo.callback(o.callback, o.scope, [o, true, r]);
11920 setTimeout(function(){document.body.removeChild(frame);}, 100);
11923 Roo.EventManager.on(frame, 'load', cb, this);
11926 if(hiddens){ // remove dynamic params
11927 for(var i = 0, len = hiddens.length; i < len; i++){
11928 form.removeChild(hiddens[i]);
11932 // this is a 'formdata version???'
11935 doFormDataUpload : function(o, url)
11939 var form = Roo.getDom(o.form);
11940 form.enctype = form.encoding = 'multipart/form-data';
11941 formData = o.formData === true ? new FormData(form) : o.formData;
11943 formData = o.formData === true ? new FormData() : o.formData;
11948 success: this.handleResponse,
11949 failure: this.handleFailure,
11951 argument: {options: o},
11952 timeout : o.timeout || this.timeout
11955 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11959 }else if(this.autoAbort !== false){
11963 //Roo.lib.Ajax.defaultPostHeader = null;
11964 Roo.lib.Ajax.useDefaultHeader = false;
11965 this.transId = Roo.lib.Ajax.request( "POST", url, cb, formData, o);
11966 Roo.lib.Ajax.useDefaultHeader = true;
11974 * Ext JS Library 1.1.1
11975 * Copyright(c) 2006-2007, Ext JS, LLC.
11977 * Originally Released Under LGPL - original licence link has changed is not relivant.
11980 * <script type="text/javascript">
11984 * Global Ajax request class.
11987 * @extends Roo.data.Connection
11990 * @cfg {String} url The default URL to be used for requests to the server. (defaults to undefined)
11991 * @cfg {Object} extraParams An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11992 * @cfg {Object} defaultHeaders An object containing request headers which are added to each request made by this object. (defaults to undefined)
11993 * @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)
11994 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11995 * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11996 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11998 Roo.Ajax = new Roo.data.Connection({
12007 * Serialize the passed form into a url encoded string
12009 * @param {String/HTMLElement} form
12012 serializeForm : function(form){
12013 return Roo.lib.Ajax.serializeForm(form);
12017 * Ext JS Library 1.1.1
12018 * Copyright(c) 2006-2007, Ext JS, LLC.
12020 * Originally Released Under LGPL - original licence link has changed is not relivant.
12023 * <script type="text/javascript">
12028 * @class Roo.UpdateManager
12029 * @extends Roo.util.Observable
12030 * Provides AJAX-style update for Element object.<br><br>
12033 * // Get it from a Roo.Element object
12034 * var el = Roo.get("foo");
12035 * var mgr = el.getUpdateManager();
12036 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
12038 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
12040 * // or directly (returns the same UpdateManager instance)
12041 * var mgr = new Roo.UpdateManager("myElementId");
12042 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
12043 * mgr.on("update", myFcnNeedsToKnow);
12045 // short handed call directly from the element object
12046 Roo.get("foo").load({
12050 text: "Loading Foo..."
12054 * Create new UpdateManager directly.
12055 * @param {String/HTMLElement/Roo.Element} el The element to update
12056 * @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).
12058 Roo.UpdateManager = function(el, forceNew){
12060 if(!forceNew && el.updateManager){
12061 return el.updateManager;
12064 * The Element object
12065 * @type Roo.Element
12069 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
12072 this.defaultUrl = null;
12076 * @event beforeupdate
12077 * Fired before an update is made, return false from your handler and the update is cancelled.
12078 * @param {Roo.Element} el
12079 * @param {String/Object/Function} url
12080 * @param {String/Object} params
12082 "beforeupdate": true,
12085 * Fired after successful update is made.
12086 * @param {Roo.Element} el
12087 * @param {Object} oResponseObject The response Object
12092 * Fired on update failure.
12093 * @param {Roo.Element} el
12094 * @param {Object} oResponseObject The response Object
12098 var d = Roo.UpdateManager.defaults;
12100 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
12103 this.sslBlankUrl = d.sslBlankUrl;
12105 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
12108 this.disableCaching = d.disableCaching;
12110 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
12113 this.indicatorText = d.indicatorText;
12115 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
12118 this.showLoadIndicator = d.showLoadIndicator;
12120 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
12123 this.timeout = d.timeout;
12126 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
12129 this.loadScripts = d.loadScripts;
12132 * Transaction object of current executing transaction
12134 this.transaction = null;
12139 this.autoRefreshProcId = null;
12141 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
12144 this.refreshDelegate = this.refresh.createDelegate(this);
12146 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
12149 this.updateDelegate = this.update.createDelegate(this);
12151 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
12154 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
12158 this.successDelegate = this.processSuccess.createDelegate(this);
12162 this.failureDelegate = this.processFailure.createDelegate(this);
12164 if(!this.renderer){
12166 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
12168 this.renderer = new Roo.UpdateManager.BasicRenderer();
12171 Roo.UpdateManager.superclass.constructor.call(this);
12174 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
12176 * Get the Element this UpdateManager is bound to
12177 * @return {Roo.Element} The element
12179 getEl : function(){
12183 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
12184 * @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:
12187 url: "your-url.php",<br/>
12188 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
12189 callback: yourFunction,<br/>
12190 scope: yourObject, //(optional scope) <br/>
12191 discardUrl: false, <br/>
12192 nocache: false,<br/>
12193 text: "Loading...",<br/>
12195 scripts: false<br/>
12198 * The only required property is url. The optional properties nocache, text and scripts
12199 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
12200 * @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}
12201 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
12202 * @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.
12204 update : function(url, params, callback, discardUrl){
12205 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
12206 var method = this.method,
12208 if(typeof url == "object"){ // must be config object
12211 params = params || cfg.params;
12212 callback = callback || cfg.callback;
12213 discardUrl = discardUrl || cfg.discardUrl;
12214 if(callback && cfg.scope){
12215 callback = callback.createDelegate(cfg.scope);
12217 if(typeof cfg.method != "undefined"){method = cfg.method;};
12218 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
12219 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
12220 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
12221 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
12223 this.showLoading();
12225 this.defaultUrl = url;
12227 if(typeof url == "function"){
12228 url = url.call(this);
12231 method = method || (params ? "POST" : "GET");
12232 if(method == "GET"){
12233 url = this.prepareUrl(url);
12236 var o = Roo.apply(cfg ||{}, {
12239 success: this.successDelegate,
12240 failure: this.failureDelegate,
12241 callback: undefined,
12242 timeout: (this.timeout*1000),
12243 argument: {"url": url, "form": null, "callback": callback, "params": params}
12245 Roo.log("updated manager called with timeout of " + o.timeout);
12246 this.transaction = Roo.Ajax.request(o);
12251 * 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.
12252 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
12253 * @param {String/HTMLElement} form The form Id or form element
12254 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
12255 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
12256 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
12258 formUpdate : function(form, url, reset, callback){
12259 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
12260 if(typeof url == "function"){
12261 url = url.call(this);
12263 form = Roo.getDom(form);
12264 this.transaction = Roo.Ajax.request({
12267 success: this.successDelegate,
12268 failure: this.failureDelegate,
12269 timeout: (this.timeout*1000),
12270 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
12272 this.showLoading.defer(1, this);
12277 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
12278 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12280 refresh : function(callback){
12281 if(this.defaultUrl == null){
12284 this.update(this.defaultUrl, null, callback, true);
12288 * Set this element to auto refresh.
12289 * @param {Number} interval How often to update (in seconds).
12290 * @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)
12291 * @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}
12292 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12293 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
12295 startAutoRefresh : function(interval, url, params, callback, refreshNow){
12297 this.update(url || this.defaultUrl, params, callback, true);
12299 if(this.autoRefreshProcId){
12300 clearInterval(this.autoRefreshProcId);
12302 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
12306 * Stop auto refresh on this element.
12308 stopAutoRefresh : function(){
12309 if(this.autoRefreshProcId){
12310 clearInterval(this.autoRefreshProcId);
12311 delete this.autoRefreshProcId;
12315 isAutoRefreshing : function(){
12316 return this.autoRefreshProcId ? true : false;
12319 * Called to update the element to "Loading" state. Override to perform custom action.
12321 showLoading : function(){
12322 if(this.showLoadIndicator){
12323 this.el.update(this.indicatorText);
12328 * Adds unique parameter to query string if disableCaching = true
12331 prepareUrl : function(url){
12332 if(this.disableCaching){
12333 var append = "_dc=" + (new Date().getTime());
12334 if(url.indexOf("?") !== -1){
12335 url += "&" + append;
12337 url += "?" + append;
12346 processSuccess : function(response){
12347 this.transaction = null;
12348 if(response.argument.form && response.argument.reset){
12349 try{ // put in try/catch since some older FF releases had problems with this
12350 response.argument.form.reset();
12353 if(this.loadScripts){
12354 this.renderer.render(this.el, response, this,
12355 this.updateComplete.createDelegate(this, [response]));
12357 this.renderer.render(this.el, response, this);
12358 this.updateComplete(response);
12362 updateComplete : function(response){
12363 this.fireEvent("update", this.el, response);
12364 if(typeof response.argument.callback == "function"){
12365 response.argument.callback(this.el, true, response);
12372 processFailure : function(response){
12373 this.transaction = null;
12374 this.fireEvent("failure", this.el, response);
12375 if(typeof response.argument.callback == "function"){
12376 response.argument.callback(this.el, false, response);
12381 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12382 * @param {Object} renderer The object implementing the render() method
12384 setRenderer : function(renderer){
12385 this.renderer = renderer;
12388 getRenderer : function(){
12389 return this.renderer;
12393 * Set the defaultUrl used for updates
12394 * @param {String/Function} defaultUrl The url or a function to call to get the url
12396 setDefaultUrl : function(defaultUrl){
12397 this.defaultUrl = defaultUrl;
12401 * Aborts the executing transaction
12403 abort : function(){
12404 if(this.transaction){
12405 Roo.Ajax.abort(this.transaction);
12410 * Returns true if an update is in progress
12411 * @return {Boolean}
12413 isUpdating : function(){
12414 if(this.transaction){
12415 return Roo.Ajax.isLoading(this.transaction);
12422 * @class Roo.UpdateManager.defaults
12423 * @static (not really - but it helps the doc tool)
12424 * The defaults collection enables customizing the default properties of UpdateManager
12426 Roo.UpdateManager.defaults = {
12428 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12434 * True to process scripts by default (Defaults to false).
12437 loadScripts : false,
12440 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12443 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12445 * Whether to append unique parameter on get request to disable caching (Defaults to false).
12448 disableCaching : false,
12450 * Whether to show indicatorText when loading (Defaults to true).
12453 showLoadIndicator : true,
12455 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
12458 indicatorText : '<div class="loading-indicator">Loading...</div>'
12462 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12464 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12465 * @param {String/HTMLElement/Roo.Element} el The element to update
12466 * @param {String} url The url
12467 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12468 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12471 * @member Roo.UpdateManager
12473 Roo.UpdateManager.updateElement = function(el, url, params, options){
12474 var um = Roo.get(el, true).getUpdateManager();
12475 Roo.apply(um, options);
12476 um.update(url, params, options ? options.callback : null);
12478 // alias for backwards compat
12479 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12481 * @class Roo.UpdateManager.BasicRenderer
12482 * Default Content renderer. Updates the elements innerHTML with the responseText.
12484 Roo.UpdateManager.BasicRenderer = function(){};
12486 Roo.UpdateManager.BasicRenderer.prototype = {
12488 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12489 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12490 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12491 * @param {Roo.Element} el The element being rendered
12492 * @param {Object} response The YUI Connect response object
12493 * @param {UpdateManager} updateManager The calling update manager
12494 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12496 render : function(el, response, updateManager, callback){
12497 el.update(response.responseText, updateManager.loadScripts, callback);
12503 * (c)) Alan Knowles
12509 * @class Roo.DomTemplate
12510 * @extends Roo.Template
12511 * An effort at a dom based template engine..
12513 * Similar to XTemplate, except it uses dom parsing to create the template..
12515 * Supported features:
12520 {a_variable} - output encoded.
12521 {a_variable.format:("Y-m-d")} - call a method on the variable
12522 {a_variable:raw} - unencoded output
12523 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12524 {a_variable:this.method_on_template(...)} - call a method on the template object.
12529 <div roo-for="a_variable or condition.."></div>
12530 <div roo-if="a_variable or condition"></div>
12531 <div roo-exec="some javascript"></div>
12532 <div roo-name="named_template"></div>
12537 Roo.DomTemplate = function()
12539 Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12546 Roo.extend(Roo.DomTemplate, Roo.Template, {
12548 * id counter for sub templates.
12552 * flag to indicate if dom parser is inside a pre,
12553 * it will strip whitespace if not.
12558 * The various sub templates
12566 * basic tag replacing syntax
12569 * // you can fake an object call by doing this
12573 re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12574 //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12576 iterChild : function (node, method) {
12578 var oldPre = this.inPre;
12579 if (node.tagName == 'PRE') {
12582 for( var i = 0; i < node.childNodes.length; i++) {
12583 method.call(this, node.childNodes[i]);
12585 this.inPre = oldPre;
12591 * compile the template
12593 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12596 compile: function()
12600 // covert the html into DOM...
12604 doc = document.implementation.createHTMLDocument("");
12605 doc.documentElement.innerHTML = this.html ;
12606 div = doc.documentElement;
12608 // old IE... - nasty -- it causes all sorts of issues.. with
12609 // images getting pulled from server..
12610 div = document.createElement('div');
12611 div.innerHTML = this.html;
12613 //doc.documentElement.innerHTML = htmlBody
12619 this.iterChild(div, function(n) {_t.compileNode(n, true); });
12621 var tpls = this.tpls;
12623 // create a top level template from the snippet..
12625 //Roo.log(div.innerHTML);
12632 body : div.innerHTML,
12645 Roo.each(tpls, function(tp){
12646 this.compileTpl(tp);
12647 this.tpls[tp.id] = tp;
12650 this.master = tpls[0];
12656 compileNode : function(node, istop) {
12661 // skip anything not a tag..
12662 if (node.nodeType != 1) {
12663 if (node.nodeType == 3 && !this.inPre) {
12664 // reduce white space..
12665 node.nodeValue = node.nodeValue.replace(/\s+/g, ' ');
12688 case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12689 case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12690 case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12691 case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12697 // just itterate children..
12698 this.iterChild(node,this.compileNode);
12701 tpl.uid = this.id++;
12702 tpl.value = node.getAttribute('roo-' + tpl.attr);
12703 node.removeAttribute('roo-'+ tpl.attr);
12704 if (tpl.attr != 'name') {
12705 var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12706 node.parentNode.replaceChild(placeholder, node);
12709 var placeholder = document.createElement('span');
12710 placeholder.className = 'roo-tpl-' + tpl.value;
12711 node.parentNode.replaceChild(placeholder, node);
12714 // parent now sees '{domtplXXXX}
12715 this.iterChild(node,this.compileNode);
12717 // we should now have node body...
12718 var div = document.createElement('div');
12719 div.appendChild(node);
12721 // this has the unfortunate side effect of converting tagged attributes
12722 // eg. href="{...}" into %7C...%7D
12723 // this has been fixed by searching for those combo's although it's a bit hacky..
12726 tpl.body = div.innerHTML;
12733 switch (tpl.value) {
12734 case '.': tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12735 case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12736 default: tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12741 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12745 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12749 tpl.id = tpl.value; // replace non characters???
12755 this.tpls.push(tpl);
12765 * Compile a segment of the template into a 'sub-template'
12771 compileTpl : function(tpl)
12773 var fm = Roo.util.Format;
12774 var useF = this.disableFormats !== true;
12776 var sep = Roo.isGecko ? "+\n" : ",\n";
12778 var undef = function(str) {
12779 Roo.debug && Roo.log("Property not found :" + str);
12783 //Roo.log(tpl.body);
12787 var fn = function(m, lbrace, name, format, args)
12790 //Roo.log(arguments);
12791 args = args ? args.replace(/\\'/g,"'") : args;
12792 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12793 if (typeof(format) == 'undefined') {
12794 format = 'htmlEncode';
12796 if (format == 'raw' ) {
12800 if(name.substr(0, 6) == 'domtpl'){
12801 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12804 // build an array of options to determine if value is undefined..
12806 // basically get 'xxxx.yyyy' then do
12807 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12808 // (function () { Roo.log("Property not found"); return ''; })() :
12813 Roo.each(name.split('.'), function(st) {
12814 lookfor += (lookfor.length ? '.': '') + st;
12815 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
12818 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12821 if(format && useF){
12823 args = args ? ',' + args : "";
12825 if(format.substr(0, 5) != "this."){
12826 format = "fm." + format + '(';
12828 format = 'this.call("'+ format.substr(5) + '", ';
12832 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
12835 if (args && args.length) {
12836 // called with xxyx.yuu:(test,test)
12838 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
12840 // raw.. - :raw modifier..
12841 return "'"+ sep + udef_st + name + ")"+sep+"'";
12845 // branched to use + in gecko and [].join() in others
12847 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
12848 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12851 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
12852 body.push(tpl.body.replace(/(\r\n|\n)/g,
12853 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12854 body.push("'].join('');};};");
12855 body = body.join('');
12858 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12860 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
12867 * same as applyTemplate, except it's done to one of the subTemplates
12868 * when using named templates, you can do:
12870 * var str = pl.applySubTemplate('your-name', values);
12873 * @param {Number} id of the template
12874 * @param {Object} values to apply to template
12875 * @param {Object} parent (normaly the instance of this object)
12877 applySubTemplate : function(id, values, parent)
12881 var t = this.tpls[id];
12885 if(t.ifCall && !t.ifCall.call(this, values, parent)){
12886 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12890 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12897 if(t.execCall && t.execCall.call(this, values, parent)){
12901 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12907 var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12908 parent = t.target ? values : parent;
12909 if(t.forCall && vs instanceof Array){
12911 for(var i = 0, len = vs.length; i < len; i++){
12913 buf[buf.length] = t.compiled.call(this, vs[i], parent);
12915 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12917 //Roo.log(t.compiled);
12921 return buf.join('');
12924 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12929 return t.compiled.call(this, vs, parent);
12931 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12933 //Roo.log(t.compiled);
12941 applyTemplate : function(values){
12942 return this.master.compiled.call(this, values, {});
12943 //var s = this.subs;
12946 apply : function(){
12947 return this.applyTemplate.apply(this, arguments);
12952 Roo.DomTemplate.from = function(el){
12953 el = Roo.getDom(el);
12954 return new Roo.Domtemplate(el.value || el.innerHTML);
12957 * Ext JS Library 1.1.1
12958 * Copyright(c) 2006-2007, Ext JS, LLC.
12960 * Originally Released Under LGPL - original licence link has changed is not relivant.
12963 * <script type="text/javascript">
12967 * @class Roo.util.DelayedTask
12968 * Provides a convenient method of performing setTimeout where a new
12969 * timeout cancels the old timeout. An example would be performing validation on a keypress.
12970 * You can use this class to buffer
12971 * the keypress events for a certain number of milliseconds, and perform only if they stop
12972 * for that amount of time.
12973 * @constructor The parameters to this constructor serve as defaults and are not required.
12974 * @param {Function} fn (optional) The default function to timeout
12975 * @param {Object} scope (optional) The default scope of that timeout
12976 * @param {Array} args (optional) The default Array of arguments
12978 Roo.util.DelayedTask = function(fn, scope, args){
12979 var id = null, d, t;
12981 var call = function(){
12982 var now = new Date().getTime();
12986 fn.apply(scope, args || []);
12990 * Cancels any pending timeout and queues a new one
12991 * @param {Number} delay The milliseconds to delay
12992 * @param {Function} newFn (optional) Overrides function passed to constructor
12993 * @param {Object} newScope (optional) Overrides scope passed to constructor
12994 * @param {Array} newArgs (optional) Overrides args passed to constructor
12996 this.delay = function(delay, newFn, newScope, newArgs){
12997 if(id && delay != d){
13001 t = new Date().getTime();
13003 scope = newScope || scope;
13004 args = newArgs || args;
13006 id = setInterval(call, d);
13011 * Cancel the last queued timeout
13013 this.cancel = function(){
13021 * Ext JS Library 1.1.1
13022 * Copyright(c) 2006-2007, Ext JS, LLC.
13024 * Originally Released Under LGPL - original licence link has changed is not relivant.
13027 * <script type="text/javascript">
13031 Roo.util.TaskRunner = function(interval){
13032 interval = interval || 10;
13033 var tasks = [], removeQueue = [];
13035 var running = false;
13037 var stopThread = function(){
13043 var startThread = function(){
13046 id = setInterval(runTasks, interval);
13050 var removeTask = function(task){
13051 removeQueue.push(task);
13057 var runTasks = function(){
13058 if(removeQueue.length > 0){
13059 for(var i = 0, len = removeQueue.length; i < len; i++){
13060 tasks.remove(removeQueue[i]);
13063 if(tasks.length < 1){
13068 var now = new Date().getTime();
13069 for(var i = 0, len = tasks.length; i < len; ++i){
13071 var itime = now - t.taskRunTime;
13072 if(t.interval <= itime){
13073 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
13074 t.taskRunTime = now;
13075 if(rt === false || t.taskRunCount === t.repeat){
13080 if(t.duration && t.duration <= (now - t.taskStartTime)){
13087 * Queues a new task.
13088 * @param {Object} task
13090 this.start = function(task){
13092 task.taskStartTime = new Date().getTime();
13093 task.taskRunTime = 0;
13094 task.taskRunCount = 0;
13099 this.stop = function(task){
13104 this.stopAll = function(){
13106 for(var i = 0, len = tasks.length; i < len; i++){
13107 if(tasks[i].onStop){
13116 Roo.TaskMgr = new Roo.util.TaskRunner();/*
13118 * Ext JS Library 1.1.1
13119 * Copyright(c) 2006-2007, Ext JS, LLC.
13121 * Originally Released Under LGPL - original licence link has changed is not relivant.
13124 * <script type="text/javascript">
13129 * @class Roo.util.MixedCollection
13130 * @extends Roo.util.Observable
13131 * A Collection class that maintains both numeric indexes and keys and exposes events.
13133 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
13134 * collection (defaults to false)
13135 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
13136 * and return the key value for that item. This is used when available to look up the key on items that
13137 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
13138 * equivalent to providing an implementation for the {@link #getKey} method.
13140 Roo.util.MixedCollection = function(allowFunctions, keyFn){
13148 * Fires when the collection is cleared.
13153 * Fires when an item is added to the collection.
13154 * @param {Number} index The index at which the item was added.
13155 * @param {Object} o The item added.
13156 * @param {String} key The key associated with the added item.
13161 * Fires when an item is replaced in the collection.
13162 * @param {String} key he key associated with the new added.
13163 * @param {Object} old The item being replaced.
13164 * @param {Object} new The new item.
13169 * Fires when an item is removed from the collection.
13170 * @param {Object} o The item being removed.
13171 * @param {String} key (optional) The key associated with the removed item.
13176 this.allowFunctions = allowFunctions === true;
13178 this.getKey = keyFn;
13180 Roo.util.MixedCollection.superclass.constructor.call(this);
13183 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
13184 allowFunctions : false,
13187 * Adds an item to the collection.
13188 * @param {String} key The key to associate with the item
13189 * @param {Object} o The item to add.
13190 * @return {Object} The item added.
13192 add : function(key, o){
13193 if(arguments.length == 1){
13195 key = this.getKey(o);
13197 if(typeof key == "undefined" || key === null){
13199 this.items.push(o);
13200 this.keys.push(null);
13202 var old = this.map[key];
13204 return this.replace(key, o);
13207 this.items.push(o);
13209 this.keys.push(key);
13211 this.fireEvent("add", this.length-1, o, key);
13216 * MixedCollection has a generic way to fetch keys if you implement getKey.
13219 var mc = new Roo.util.MixedCollection();
13220 mc.add(someEl.dom.id, someEl);
13221 mc.add(otherEl.dom.id, otherEl);
13225 var mc = new Roo.util.MixedCollection();
13226 mc.getKey = function(el){
13232 // or via the constructor
13233 var mc = new Roo.util.MixedCollection(false, function(el){
13239 * @param o {Object} The item for which to find the key.
13240 * @return {Object} The key for the passed item.
13242 getKey : function(o){
13247 * Replaces an item in the collection.
13248 * @param {String} key The key associated with the item to replace, or the item to replace.
13249 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
13250 * @return {Object} The new item.
13252 replace : function(key, o){
13253 if(arguments.length == 1){
13255 key = this.getKey(o);
13257 var old = this.item(key);
13258 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
13259 return this.add(key, o);
13261 var index = this.indexOfKey(key);
13262 this.items[index] = o;
13264 this.fireEvent("replace", key, old, o);
13269 * Adds all elements of an Array or an Object to the collection.
13270 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
13271 * an Array of values, each of which are added to the collection.
13273 addAll : function(objs){
13274 if(arguments.length > 1 || objs instanceof Array){
13275 var args = arguments.length > 1 ? arguments : objs;
13276 for(var i = 0, len = args.length; i < len; i++){
13280 for(var key in objs){
13281 if(this.allowFunctions || typeof objs[key] != "function"){
13282 this.add(key, objs[key]);
13289 * Executes the specified function once for every item in the collection, passing each
13290 * item as the first and only parameter. returning false from the function will stop the iteration.
13291 * @param {Function} fn The function to execute for each item.
13292 * @param {Object} scope (optional) The scope in which to execute the function.
13294 each : function(fn, scope){
13295 var items = [].concat(this.items); // each safe for removal
13296 for(var i = 0, len = items.length; i < len; i++){
13297 if(fn.call(scope || items[i], items[i], i, len) === false){
13304 * Executes the specified function once for every key in the collection, passing each
13305 * key, and its associated item as the first two parameters.
13306 * @param {Function} fn The function to execute for each item.
13307 * @param {Object} scope (optional) The scope in which to execute the function.
13309 eachKey : function(fn, scope){
13310 for(var i = 0, len = this.keys.length; i < len; i++){
13311 fn.call(scope || window, this.keys[i], this.items[i], i, len);
13316 * Returns the first item in the collection which elicits a true return value from the
13317 * passed selection function.
13318 * @param {Function} fn The selection function to execute for each item.
13319 * @param {Object} scope (optional) The scope in which to execute the function.
13320 * @return {Object} The first item in the collection which returned true from the selection function.
13322 find : function(fn, scope){
13323 for(var i = 0, len = this.items.length; i < len; i++){
13324 if(fn.call(scope || window, this.items[i], this.keys[i])){
13325 return this.items[i];
13332 * Inserts an item at the specified index in the collection.
13333 * @param {Number} index The index to insert the item at.
13334 * @param {String} key The key to associate with the new item, or the item itself.
13335 * @param {Object} o (optional) If the second parameter was a key, the new item.
13336 * @return {Object} The item inserted.
13338 insert : function(index, key, o){
13339 if(arguments.length == 2){
13341 key = this.getKey(o);
13343 if(index >= this.length){
13344 return this.add(key, o);
13347 this.items.splice(index, 0, o);
13348 if(typeof key != "undefined" && key != null){
13351 this.keys.splice(index, 0, key);
13352 this.fireEvent("add", index, o, key);
13357 * Removed an item from the collection.
13358 * @param {Object} o The item to remove.
13359 * @return {Object} The item removed.
13361 remove : function(o){
13362 return this.removeAt(this.indexOf(o));
13366 * Remove an item from a specified index in the collection.
13367 * @param {Number} index The index within the collection of the item to remove.
13369 removeAt : function(index){
13370 if(index < this.length && index >= 0){
13372 var o = this.items[index];
13373 this.items.splice(index, 1);
13374 var key = this.keys[index];
13375 if(typeof key != "undefined"){
13376 delete this.map[key];
13378 this.keys.splice(index, 1);
13379 this.fireEvent("remove", o, key);
13384 * Removed an item associated with the passed key fom the collection.
13385 * @param {String} key The key of the item to remove.
13387 removeKey : function(key){
13388 return this.removeAt(this.indexOfKey(key));
13392 * Returns the number of items in the collection.
13393 * @return {Number} the number of items in the collection.
13395 getCount : function(){
13396 return this.length;
13400 * Returns index within the collection of the passed Object.
13401 * @param {Object} o The item to find the index of.
13402 * @return {Number} index of the item.
13404 indexOf : function(o){
13405 if(!this.items.indexOf){
13406 for(var i = 0, len = this.items.length; i < len; i++){
13407 if(this.items[i] == o) {
13413 return this.items.indexOf(o);
13418 * Returns index within the collection of the passed key.
13419 * @param {String} key The key to find the index of.
13420 * @return {Number} index of the key.
13422 indexOfKey : function(key){
13423 if(!this.keys.indexOf){
13424 for(var i = 0, len = this.keys.length; i < len; i++){
13425 if(this.keys[i] == key) {
13431 return this.keys.indexOf(key);
13436 * Returns the item associated with the passed key OR index. Key has priority over index.
13437 * @param {String/Number} key The key or index of the item.
13438 * @return {Object} The item associated with the passed key.
13440 item : function(key){
13441 if (key === 'length') {
13444 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13445 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13449 * Returns the item at the specified index.
13450 * @param {Number} index The index of the item.
13453 itemAt : function(index){
13454 return this.items[index];
13458 * Returns the item associated with the passed key.
13459 * @param {String/Number} key The key of the item.
13460 * @return {Object} The item associated with the passed key.
13462 key : function(key){
13463 return this.map[key];
13467 * Returns true if the collection contains the passed Object as an item.
13468 * @param {Object} o The Object to look for in the collection.
13469 * @return {Boolean} True if the collection contains the Object as an item.
13471 contains : function(o){
13472 return this.indexOf(o) != -1;
13476 * Returns true if the collection contains the passed Object as a key.
13477 * @param {String} key The key to look for in the collection.
13478 * @return {Boolean} True if the collection contains the Object as a key.
13480 containsKey : function(key){
13481 return typeof this.map[key] != "undefined";
13485 * Removes all items from the collection.
13487 clear : function(){
13492 this.fireEvent("clear");
13496 * Returns the first item in the collection.
13497 * @return {Object} the first item in the collection..
13499 first : function(){
13500 return this.items[0];
13504 * Returns the last item in the collection.
13505 * @return {Object} the last item in the collection..
13508 return this.items[this.length-1];
13511 _sort : function(property, dir, fn){
13512 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13513 fn = fn || function(a, b){
13516 var c = [], k = this.keys, items = this.items;
13517 for(var i = 0, len = items.length; i < len; i++){
13518 c[c.length] = {key: k[i], value: items[i], index: i};
13520 c.sort(function(a, b){
13521 var v = fn(a[property], b[property]) * dsc;
13523 v = (a.index < b.index ? -1 : 1);
13527 for(var i = 0, len = c.length; i < len; i++){
13528 items[i] = c[i].value;
13531 this.fireEvent("sort", this);
13535 * Sorts this collection with the passed comparison function
13536 * @param {String} direction (optional) "ASC" or "DESC"
13537 * @param {Function} fn (optional) comparison function
13539 sort : function(dir, fn){
13540 this._sort("value", dir, fn);
13544 * Sorts this collection by keys
13545 * @param {String} direction (optional) "ASC" or "DESC"
13546 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13548 keySort : function(dir, fn){
13549 this._sort("key", dir, fn || function(a, b){
13550 return String(a).toUpperCase()-String(b).toUpperCase();
13555 * Returns a range of items in this collection
13556 * @param {Number} startIndex (optional) defaults to 0
13557 * @param {Number} endIndex (optional) default to the last item
13558 * @return {Array} An array of items
13560 getRange : function(start, end){
13561 var items = this.items;
13562 if(items.length < 1){
13565 start = start || 0;
13566 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13569 for(var i = start; i <= end; i++) {
13570 r[r.length] = items[i];
13573 for(var i = start; i >= end; i--) {
13574 r[r.length] = items[i];
13581 * Filter the <i>objects</i> in this collection by a specific property.
13582 * Returns a new collection that has been filtered.
13583 * @param {String} property A property on your objects
13584 * @param {String/RegExp} value Either string that the property values
13585 * should start with or a RegExp to test against the property
13586 * @return {MixedCollection} The new filtered collection
13588 filter : function(property, value){
13589 if(!value.exec){ // not a regex
13590 value = String(value);
13591 if(value.length == 0){
13592 return this.clone();
13594 value = new RegExp("^" + Roo.escapeRe(value), "i");
13596 return this.filterBy(function(o){
13597 return o && value.test(o[property]);
13602 * Filter by a function. * Returns a new collection that has been filtered.
13603 * The passed function will be called with each
13604 * object in the collection. If the function returns true, the value is included
13605 * otherwise it is filtered.
13606 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13607 * @param {Object} scope (optional) The scope of the function (defaults to this)
13608 * @return {MixedCollection} The new filtered collection
13610 filterBy : function(fn, scope){
13611 var r = new Roo.util.MixedCollection();
13612 r.getKey = this.getKey;
13613 var k = this.keys, it = this.items;
13614 for(var i = 0, len = it.length; i < len; i++){
13615 if(fn.call(scope||this, it[i], k[i])){
13616 r.add(k[i], it[i]);
13623 * Creates a duplicate of this collection
13624 * @return {MixedCollection}
13626 clone : function(){
13627 var r = new Roo.util.MixedCollection();
13628 var k = this.keys, it = this.items;
13629 for(var i = 0, len = it.length; i < len; i++){
13630 r.add(k[i], it[i]);
13632 r.getKey = this.getKey;
13637 * Returns the item associated with the passed key or index.
13639 * @param {String/Number} key The key or index of the item.
13640 * @return {Object} The item associated with the passed key.
13642 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13644 * Ext JS Library 1.1.1
13645 * Copyright(c) 2006-2007, Ext JS, LLC.
13647 * Originally Released Under LGPL - original licence link has changed is not relivant.
13650 * <script type="text/javascript">
13653 * @class Roo.util.JSON
13654 * Modified version of Douglas Crockford"s json.js that doesn"t
13655 * mess with the Object prototype
13656 * http://www.json.org/js.html
13659 Roo.util.JSON = new (function(){
13660 var useHasOwn = {}.hasOwnProperty ? true : false;
13662 // crashes Safari in some instances
13663 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13665 var pad = function(n) {
13666 return n < 10 ? "0" + n : n;
13679 var encodeString = function(s){
13680 if (/["\\\x00-\x1f]/.test(s)) {
13681 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13686 c = b.charCodeAt();
13688 Math.floor(c / 16).toString(16) +
13689 (c % 16).toString(16);
13692 return '"' + s + '"';
13695 var encodeArray = function(o){
13696 var a = ["["], b, i, l = o.length, v;
13697 for (i = 0; i < l; i += 1) {
13699 switch (typeof v) {
13708 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13716 var encodeDate = function(o){
13717 return '"' + o.getFullYear() + "-" +
13718 pad(o.getMonth() + 1) + "-" +
13719 pad(o.getDate()) + "T" +
13720 pad(o.getHours()) + ":" +
13721 pad(o.getMinutes()) + ":" +
13722 pad(o.getSeconds()) + '"';
13726 * Encodes an Object, Array or other value
13727 * @param {Mixed} o The variable to encode
13728 * @return {String} The JSON string
13730 this.encode = function(o)
13732 // should this be extended to fully wrap stringify..
13734 if(typeof o == "undefined" || o === null){
13736 }else if(o instanceof Array){
13737 return encodeArray(o);
13738 }else if(o instanceof Date){
13739 return encodeDate(o);
13740 }else if(typeof o == "string"){
13741 return encodeString(o);
13742 }else if(typeof o == "number"){
13743 return isFinite(o) ? String(o) : "null";
13744 }else if(typeof o == "boolean"){
13747 var a = ["{"], b, i, v;
13749 if(!useHasOwn || o.hasOwnProperty(i)) {
13751 switch (typeof v) {
13760 a.push(this.encode(i), ":",
13761 v === null ? "null" : this.encode(v));
13772 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13773 * @param {String} json The JSON string
13774 * @return {Object} The resulting object
13776 this.decode = function(json){
13778 return /** eval:var:json */ eval("(" + json + ')');
13782 * Shorthand for {@link Roo.util.JSON#encode}
13783 * @member Roo encode
13785 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13787 * Shorthand for {@link Roo.util.JSON#decode}
13788 * @member Roo decode
13790 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13793 * Ext JS Library 1.1.1
13794 * Copyright(c) 2006-2007, Ext JS, LLC.
13796 * Originally Released Under LGPL - original licence link has changed is not relivant.
13799 * <script type="text/javascript">
13803 * @class Roo.util.Format
13804 * Reusable data formatting functions
13807 Roo.util.Format = function(){
13808 var trimRe = /^\s+|\s+$/g;
13811 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13812 * @param {String} value The string to truncate
13813 * @param {Number} length The maximum length to allow before truncating
13814 * @return {String} The converted text
13816 ellipsis : function(value, len){
13817 if(value && value.length > len){
13818 return value.substr(0, len-3)+"...";
13824 * Checks a reference and converts it to empty string if it is undefined
13825 * @param {Mixed} value Reference to check
13826 * @return {Mixed} Empty string if converted, otherwise the original value
13828 undef : function(value){
13829 return typeof value != "undefined" ? value : "";
13833 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13834 * @param {String} value The string to encode
13835 * @return {String} The encoded text
13837 htmlEncode : function(value){
13838 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
13842 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13843 * @param {String} value The string to decode
13844 * @return {String} The decoded text
13846 htmlDecode : function(value){
13847 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
13851 * Trims any whitespace from either side of a string
13852 * @param {String} value The text to trim
13853 * @return {String} The trimmed text
13855 trim : function(value){
13856 return String(value).replace(trimRe, "");
13860 * Returns a substring from within an original string
13861 * @param {String} value The original text
13862 * @param {Number} start The start index of the substring
13863 * @param {Number} length The length of the substring
13864 * @return {String} The substring
13866 substr : function(value, start, length){
13867 return String(value).substr(start, length);
13871 * Converts a string to all lower case letters
13872 * @param {String} value The text to convert
13873 * @return {String} The converted text
13875 lowercase : function(value){
13876 return String(value).toLowerCase();
13880 * Converts a string to all upper case letters
13881 * @param {String} value The text to convert
13882 * @return {String} The converted text
13884 uppercase : function(value){
13885 return String(value).toUpperCase();
13889 * Converts the first character only of a string to upper case
13890 * @param {String} value The text to convert
13891 * @return {String} The converted text
13893 capitalize : function(value){
13894 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13898 call : function(value, fn){
13899 if(arguments.length > 2){
13900 var args = Array.prototype.slice.call(arguments, 2);
13901 args.unshift(value);
13903 return /** eval:var:value */ eval(fn).apply(window, args);
13905 /** eval:var:value */
13906 return /** eval:var:value */ eval(fn).call(window, value);
13912 * safer version of Math.toFixed..??/
13913 * @param {Number/String} value The numeric value to format
13914 * @param {Number/String} value Decimal places
13915 * @return {String} The formatted currency string
13917 toFixed : function(v, n)
13919 // why not use to fixed - precision is buggered???
13921 return Math.round(v-0);
13923 var fact = Math.pow(10,n+1);
13924 v = (Math.round((v-0)*fact))/fact;
13925 var z = (''+fact).substring(2);
13926 if (v == Math.floor(v)) {
13927 return Math.floor(v) + '.' + z;
13930 // now just padd decimals..
13931 var ps = String(v).split('.');
13932 var fd = (ps[1] + z);
13933 var r = fd.substring(0,n);
13934 var rm = fd.substring(n);
13936 return ps[0] + '.' + r;
13938 r*=1; // turn it into a number;
13940 if (String(r).length != n) {
13943 r = String(r).substring(1); // chop the end off.
13946 return ps[0] + '.' + r;
13951 * Format a number as US currency
13952 * @param {Number/String} value The numeric value to format
13953 * @return {String} The formatted currency string
13955 usMoney : function(v){
13956 return '$' + Roo.util.Format.number(v);
13961 * eventually this should probably emulate php's number_format
13962 * @param {Number/String} value The numeric value to format
13963 * @param {Number} decimals number of decimal places
13964 * @param {String} delimiter for thousands (default comma)
13965 * @return {String} The formatted currency string
13967 number : function(v, decimals, thousandsDelimiter)
13969 // multiply and round.
13970 decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13971 thousandsDelimiter = typeof(thousandsDelimiter) == 'undefined' ? ',' : thousandsDelimiter;
13973 var mul = Math.pow(10, decimals);
13974 var zero = String(mul).substring(1);
13975 v = (Math.round((v-0)*mul))/mul;
13977 // if it's '0' number.. then
13979 //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13981 var ps = v.split('.');
13984 var r = /(\d+)(\d{3})/;
13987 if(thousandsDelimiter.length != 0) {
13988 whole = whole.replace(/\B(?=(\d{3})+(?!\d))/g, thousandsDelimiter );
13993 (decimals ? ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13994 // does not have decimals
13995 (decimals ? ('.' + zero) : '');
13998 return whole + sub ;
14002 * Parse a value into a formatted date using the specified format pattern.
14003 * @param {Mixed} value The value to format
14004 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
14005 * @return {String} The formatted date string
14007 date : function(v, format){
14011 if(!(v instanceof Date)){
14012 v = new Date(Date.parse(v));
14014 return v.dateFormat(format || Roo.util.Format.defaults.date);
14018 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
14019 * @param {String} format Any valid date format string
14020 * @return {Function} The date formatting function
14022 dateRenderer : function(format){
14023 return function(v){
14024 return Roo.util.Format.date(v, format);
14029 stripTagsRE : /<\/?[^>]+>/gi,
14032 * Strips all HTML tags
14033 * @param {Mixed} value The text from which to strip tags
14034 * @return {String} The stripped text
14036 stripTags : function(v){
14037 return !v ? v : String(v).replace(this.stripTagsRE, "");
14041 * Size in Mb,Gb etc.
14042 * @param {Number} value The number to be formated
14043 * @param {number} decimals how many decimal places
14044 * @return {String} the formated string
14046 size : function(value, decimals)
14048 var sizes = ['b', 'k', 'M', 'G', 'T'];
14052 var i = parseInt(Math.floor(Math.log(value) / Math.log(1024)));
14053 return Roo.util.Format.number(value/ Math.pow(1024, i) ,decimals) + sizes[i];
14060 Roo.util.Format.defaults = {
14064 * Ext JS Library 1.1.1
14065 * Copyright(c) 2006-2007, Ext JS, LLC.
14067 * Originally Released Under LGPL - original licence link has changed is not relivant.
14070 * <script type="text/javascript">
14077 * @class Roo.MasterTemplate
14078 * @extends Roo.Template
14079 * Provides a template that can have child templates. The syntax is:
14081 var t = new Roo.MasterTemplate(
14082 '<select name="{name}">',
14083 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
14086 t.add('options', {value: 'foo', text: 'bar'});
14087 // or you can add multiple child elements in one shot
14088 t.addAll('options', [
14089 {value: 'foo', text: 'bar'},
14090 {value: 'foo2', text: 'bar2'},
14091 {value: 'foo3', text: 'bar3'}
14093 // then append, applying the master template values
14094 t.append('my-form', {name: 'my-select'});
14096 * A name attribute for the child template is not required if you have only one child
14097 * template or you want to refer to them by index.
14099 Roo.MasterTemplate = function(){
14100 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
14101 this.originalHtml = this.html;
14103 var m, re = this.subTemplateRe;
14106 while(m = re.exec(this.html)){
14107 var name = m[1], content = m[2];
14112 tpl : new Roo.Template(content)
14115 st[name] = st[subIndex];
14117 st[subIndex].tpl.compile();
14118 st[subIndex].tpl.call = this.call.createDelegate(this);
14121 this.subCount = subIndex;
14124 Roo.extend(Roo.MasterTemplate, Roo.Template, {
14126 * The regular expression used to match sub templates
14130 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
14133 * Applies the passed values to a child template.
14134 * @param {String/Number} name (optional) The name or index of the child template
14135 * @param {Array/Object} values The values to be applied to the template
14136 * @return {MasterTemplate} this
14138 add : function(name, values){
14139 if(arguments.length == 1){
14140 values = arguments[0];
14143 var s = this.subs[name];
14144 s.buffer[s.buffer.length] = s.tpl.apply(values);
14149 * Applies all the passed values to a child template.
14150 * @param {String/Number} name (optional) The name or index of the child template
14151 * @param {Array} values The values to be applied to the template, this should be an array of objects.
14152 * @param {Boolean} reset (optional) True to reset the template first
14153 * @return {MasterTemplate} this
14155 fill : function(name, values, reset){
14157 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
14165 for(var i = 0, len = values.length; i < len; i++){
14166 this.add(name, values[i]);
14172 * Resets the template for reuse
14173 * @return {MasterTemplate} this
14175 reset : function(){
14177 for(var i = 0; i < this.subCount; i++){
14183 applyTemplate : function(values){
14185 var replaceIndex = -1;
14186 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
14187 return s[++replaceIndex].buffer.join("");
14189 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
14192 apply : function(){
14193 return this.applyTemplate.apply(this, arguments);
14196 compile : function(){return this;}
14200 * Alias for fill().
14203 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
14205 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
14206 * var tpl = Roo.MasterTemplate.from('element-id');
14207 * @param {String/HTMLElement} el
14208 * @param {Object} config
14211 Roo.MasterTemplate.from = function(el, config){
14212 el = Roo.getDom(el);
14213 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
14216 * Ext JS Library 1.1.1
14217 * Copyright(c) 2006-2007, Ext JS, LLC.
14219 * Originally Released Under LGPL - original licence link has changed is not relivant.
14222 * <script type="text/javascript">
14227 * @class Roo.util.CSS
14228 * Utility class for manipulating CSS rules
14231 Roo.util.CSS = function(){
14233 var doc = document;
14235 var camelRe = /(-[a-z])/gi;
14236 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
14240 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
14241 * tag and appended to the HEAD of the document.
14242 * @param {String|Object} cssText The text containing the css rules
14243 * @param {String} id An id to add to the stylesheet for later removal
14244 * @return {StyleSheet}
14246 createStyleSheet : function(cssText, id){
14248 var head = doc.getElementsByTagName("head")[0];
14249 var nrules = doc.createElement("style");
14250 nrules.setAttribute("type", "text/css");
14252 nrules.setAttribute("id", id);
14254 if (typeof(cssText) != 'string') {
14255 // support object maps..
14256 // not sure if this a good idea..
14257 // perhaps it should be merged with the general css handling
14258 // and handle js style props.
14259 var cssTextNew = [];
14260 for(var n in cssText) {
14262 for(var k in cssText[n]) {
14263 citems.push( k + ' : ' +cssText[n][k] + ';' );
14265 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
14268 cssText = cssTextNew.join("\n");
14274 head.appendChild(nrules);
14275 ss = nrules.styleSheet;
14276 ss.cssText = cssText;
14279 nrules.appendChild(doc.createTextNode(cssText));
14281 nrules.cssText = cssText;
14283 head.appendChild(nrules);
14284 ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
14286 this.cacheStyleSheet(ss);
14291 * Removes a style or link tag by id
14292 * @param {String} id The id of the tag
14294 removeStyleSheet : function(id){
14295 var existing = doc.getElementById(id);
14297 existing.parentNode.removeChild(existing);
14302 * Dynamically swaps an existing stylesheet reference for a new one
14303 * @param {String} id The id of an existing link tag to remove
14304 * @param {String} url The href of the new stylesheet to include
14306 swapStyleSheet : function(id, url){
14307 this.removeStyleSheet(id);
14308 var ss = doc.createElement("link");
14309 ss.setAttribute("rel", "stylesheet");
14310 ss.setAttribute("type", "text/css");
14311 ss.setAttribute("id", id);
14312 ss.setAttribute("href", url);
14313 doc.getElementsByTagName("head")[0].appendChild(ss);
14317 * Refresh the rule cache if you have dynamically added stylesheets
14318 * @return {Object} An object (hash) of rules indexed by selector
14320 refreshCache : function(){
14321 return this.getRules(true);
14325 cacheStyleSheet : function(stylesheet){
14329 try{// try catch for cross domain access issue
14330 var ssRules = stylesheet.cssRules || stylesheet.rules;
14331 for(var j = ssRules.length-1; j >= 0; --j){
14332 rules[ssRules[j].selectorText] = ssRules[j];
14338 * Gets all css rules for the document
14339 * @param {Boolean} refreshCache true to refresh the internal cache
14340 * @return {Object} An object (hash) of rules indexed by selector
14342 getRules : function(refreshCache){
14343 if(rules == null || refreshCache){
14345 var ds = doc.styleSheets;
14346 for(var i =0, len = ds.length; i < len; i++){
14348 this.cacheStyleSheet(ds[i]);
14356 * Gets an an individual CSS rule by selector(s)
14357 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
14358 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
14359 * @return {CSSRule} The CSS rule or null if one is not found
14361 getRule : function(selector, refreshCache){
14362 var rs = this.getRules(refreshCache);
14363 if(!(selector instanceof Array)){
14364 return rs[selector];
14366 for(var i = 0; i < selector.length; i++){
14367 if(rs[selector[i]]){
14368 return rs[selector[i]];
14376 * Updates a rule property
14377 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
14378 * @param {String} property The css property
14379 * @param {String} value The new value for the property
14380 * @return {Boolean} true If a rule was found and updated
14382 updateRule : function(selector, property, value){
14383 if(!(selector instanceof Array)){
14384 var rule = this.getRule(selector);
14386 rule.style[property.replace(camelRe, camelFn)] = value;
14390 for(var i = 0; i < selector.length; i++){
14391 if(this.updateRule(selector[i], property, value)){
14401 * Ext JS Library 1.1.1
14402 * Copyright(c) 2006-2007, Ext JS, LLC.
14404 * Originally Released Under LGPL - original licence link has changed is not relivant.
14407 * <script type="text/javascript">
14413 * @class Roo.util.ClickRepeater
14414 * @extends Roo.util.Observable
14416 * A wrapper class which can be applied to any element. Fires a "click" event while the
14417 * mouse is pressed. The interval between firings may be specified in the config but
14418 * defaults to 10 milliseconds.
14420 * Optionally, a CSS class may be applied to the element during the time it is pressed.
14422 * @cfg {String/HTMLElement/Element} el The element to act as a button.
14423 * @cfg {Number} delay The initial delay before the repeating event begins firing.
14424 * Similar to an autorepeat key delay.
14425 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14426 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14427 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14428 * "interval" and "delay" are ignored. "immediate" is honored.
14429 * @cfg {Boolean} preventDefault True to prevent the default click event
14430 * @cfg {Boolean} stopDefault True to stop the default click event
14433 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
14434 * 2007-02-02 jvs Renamed to ClickRepeater
14435 * 2007-02-03 jvs Modifications for FF Mac and Safari
14438 * @param {String/HTMLElement/Element} el The element to listen on
14439 * @param {Object} config
14441 Roo.util.ClickRepeater = function(el, config)
14443 this.el = Roo.get(el);
14444 this.el.unselectable();
14446 Roo.apply(this, config);
14451 * Fires when the mouse button is depressed.
14452 * @param {Roo.util.ClickRepeater} this
14454 "mousedown" : true,
14457 * Fires on a specified interval during the time the element is pressed.
14458 * @param {Roo.util.ClickRepeater} this
14463 * Fires when the mouse key is released.
14464 * @param {Roo.util.ClickRepeater} this
14469 this.el.on("mousedown", this.handleMouseDown, this);
14470 if(this.preventDefault || this.stopDefault){
14471 this.el.on("click", function(e){
14472 if(this.preventDefault){
14473 e.preventDefault();
14475 if(this.stopDefault){
14481 // allow inline handler
14483 this.on("click", this.handler, this.scope || this);
14486 Roo.util.ClickRepeater.superclass.constructor.call(this);
14489 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14492 preventDefault : true,
14493 stopDefault : false,
14497 handleMouseDown : function(){
14498 clearTimeout(this.timer);
14500 if(this.pressClass){
14501 this.el.addClass(this.pressClass);
14503 this.mousedownTime = new Date();
14505 Roo.get(document).on("mouseup", this.handleMouseUp, this);
14506 this.el.on("mouseout", this.handleMouseOut, this);
14508 this.fireEvent("mousedown", this);
14509 this.fireEvent("click", this);
14511 this.timer = this.click.defer(this.delay || this.interval, this);
14515 click : function(){
14516 this.fireEvent("click", this);
14517 this.timer = this.click.defer(this.getInterval(), this);
14521 getInterval: function(){
14522 if(!this.accelerate){
14523 return this.interval;
14525 var pressTime = this.mousedownTime.getElapsed();
14526 if(pressTime < 500){
14528 }else if(pressTime < 1700){
14530 }else if(pressTime < 2600){
14532 }else if(pressTime < 3500){
14534 }else if(pressTime < 4400){
14536 }else if(pressTime < 5300){
14538 }else if(pressTime < 6200){
14546 handleMouseOut : function(){
14547 clearTimeout(this.timer);
14548 if(this.pressClass){
14549 this.el.removeClass(this.pressClass);
14551 this.el.on("mouseover", this.handleMouseReturn, this);
14555 handleMouseReturn : function(){
14556 this.el.un("mouseover", this.handleMouseReturn);
14557 if(this.pressClass){
14558 this.el.addClass(this.pressClass);
14564 handleMouseUp : function(){
14565 clearTimeout(this.timer);
14566 this.el.un("mouseover", this.handleMouseReturn);
14567 this.el.un("mouseout", this.handleMouseOut);
14568 Roo.get(document).un("mouseup", this.handleMouseUp);
14569 this.el.removeClass(this.pressClass);
14570 this.fireEvent("mouseup", this);
14573 * @class Roo.util.Clipboard
14579 Roo.util.Clipboard = {
14581 * Writes a string to the clipboard - using the Clipboard API if https, otherwise using text area.
14582 * @param {String} text to copy to clipboard
14584 write : function(text) {
14585 // navigator clipboard api needs a secure context (https)
14586 if (navigator.clipboard && window.isSecureContext) {
14587 // navigator clipboard api method'
14588 navigator.clipboard.writeText(text);
14591 // text area method
14592 var ta = document.createElement("textarea");
14594 // make the textarea out of viewport
14595 ta.style.position = "fixed";
14596 ta.style.left = "-999999px";
14597 ta.style.top = "-999999px";
14598 document.body.appendChild(ta);
14601 document.execCommand('copy');
14611 * Ext JS Library 1.1.1
14612 * Copyright(c) 2006-2007, Ext JS, LLC.
14614 * Originally Released Under LGPL - original licence link has changed is not relivant.
14617 * <script type="text/javascript">
14622 * @class Roo.KeyNav
14623 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
14624 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14625 * way to implement custom navigation schemes for any UI component.</p>
14626 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14627 * pageUp, pageDown, del, home, end. Usage:</p>
14629 var nav = new Roo.KeyNav("my-element", {
14630 "left" : function(e){
14631 this.moveLeft(e.ctrlKey);
14633 "right" : function(e){
14634 this.moveRight(e.ctrlKey);
14636 "enter" : function(e){
14643 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14644 * @param {Object} config The config
14646 Roo.KeyNav = function(el, config){
14647 this.el = Roo.get(el);
14648 Roo.apply(this, config);
14649 if(!this.disabled){
14650 this.disabled = true;
14655 Roo.KeyNav.prototype = {
14657 * @cfg {Boolean} disabled
14658 * True to disable this KeyNav instance (defaults to false)
14662 * @cfg {String} defaultEventAction
14663 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
14664 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14665 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14667 defaultEventAction: "stopEvent",
14669 * @cfg {Boolean} forceKeyDown
14670 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
14671 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14672 * handle keydown instead of keypress.
14674 forceKeyDown : false,
14677 prepareEvent : function(e){
14678 var k = e.getKey();
14679 var h = this.keyToHandler[k];
14680 //if(h && this[h]){
14681 // e.stopPropagation();
14683 if(Roo.isSafari && h && k >= 37 && k <= 40){
14689 relay : function(e){
14690 var k = e.getKey();
14691 var h = this.keyToHandler[k];
14693 if(this.doRelay(e, this[h], h) !== true){
14694 e[this.defaultEventAction]();
14700 doRelay : function(e, h, hname){
14701 return h.call(this.scope || this, e);
14704 // possible handlers
14718 // quick lookup hash
14735 * Enable this KeyNav
14737 enable: function(){
14739 // ie won't do special keys on keypress, no one else will repeat keys with keydown
14740 // the EventObject will normalize Safari automatically
14741 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14742 this.el.on("keydown", this.relay, this);
14744 this.el.on("keydown", this.prepareEvent, this);
14745 this.el.on("keypress", this.relay, this);
14747 this.disabled = false;
14752 * Disable this KeyNav
14754 disable: function(){
14755 if(!this.disabled){
14756 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14757 this.el.un("keydown", this.relay);
14759 this.el.un("keydown", this.prepareEvent);
14760 this.el.un("keypress", this.relay);
14762 this.disabled = true;
14767 * Ext JS Library 1.1.1
14768 * Copyright(c) 2006-2007, Ext JS, LLC.
14770 * Originally Released Under LGPL - original licence link has changed is not relivant.
14773 * <script type="text/javascript">
14778 * @class Roo.KeyMap
14779 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14780 * The constructor accepts the same config object as defined by {@link #addBinding}.
14781 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14782 * combination it will call the function with this signature (if the match is a multi-key
14783 * combination the callback will still be called only once): (String key, Roo.EventObject e)
14784 * A KeyMap can also handle a string representation of keys.<br />
14787 // map one key by key code
14788 var map = new Roo.KeyMap("my-element", {
14789 key: 13, // or Roo.EventObject.ENTER
14794 // map multiple keys to one action by string
14795 var map = new Roo.KeyMap("my-element", {
14801 // map multiple keys to multiple actions by strings and array of codes
14802 var map = new Roo.KeyMap("my-element", [
14805 fn: function(){ alert("Return was pressed"); }
14808 fn: function(){ alert('a, b or c was pressed'); }
14813 fn: function(){ alert('Control + shift + tab was pressed.'); }
14817 * <b>Note: A KeyMap starts enabled</b>
14819 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14820 * @param {Object} config The config (see {@link #addBinding})
14821 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14823 Roo.KeyMap = function(el, config, eventName){
14824 this.el = Roo.get(el);
14825 this.eventName = eventName || "keydown";
14826 this.bindings = [];
14828 this.addBinding(config);
14833 Roo.KeyMap.prototype = {
14835 * True to stop the event from bubbling and prevent the default browser action if the
14836 * key was handled by the KeyMap (defaults to false)
14842 * Add a new binding to this KeyMap. The following config object properties are supported:
14844 Property Type Description
14845 ---------- --------------- ----------------------------------------------------------------------
14846 key String/Array A single keycode or an array of keycodes to handle
14847 shift Boolean True to handle key only when shift is pressed (defaults to false)
14848 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
14849 alt Boolean True to handle key only when alt is pressed (defaults to false)
14850 fn Function The function to call when KeyMap finds the expected key combination
14851 scope Object The scope of the callback function
14857 var map = new Roo.KeyMap(document, {
14858 key: Roo.EventObject.ENTER,
14863 //Add a new binding to the existing KeyMap later
14871 * @param {Object/Array} config A single KeyMap config or an array of configs
14873 addBinding : function(config){
14874 if(config instanceof Array){
14875 for(var i = 0, len = config.length; i < len; i++){
14876 this.addBinding(config[i]);
14880 var keyCode = config.key,
14881 shift = config.shift,
14882 ctrl = config.ctrl,
14885 scope = config.scope;
14886 if(typeof keyCode == "string"){
14888 var keyString = keyCode.toUpperCase();
14889 for(var j = 0, len = keyString.length; j < len; j++){
14890 ks.push(keyString.charCodeAt(j));
14894 var keyArray = keyCode instanceof Array;
14895 var handler = function(e){
14896 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
14897 var k = e.getKey();
14899 for(var i = 0, len = keyCode.length; i < len; i++){
14900 if(keyCode[i] == k){
14901 if(this.stopEvent){
14904 fn.call(scope || window, k, e);
14910 if(this.stopEvent){
14913 fn.call(scope || window, k, e);
14918 this.bindings.push(handler);
14922 * Shorthand for adding a single key listener
14923 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14924 * following options:
14925 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14926 * @param {Function} fn The function to call
14927 * @param {Object} scope (optional) The scope of the function
14929 on : function(key, fn, scope){
14930 var keyCode, shift, ctrl, alt;
14931 if(typeof key == "object" && !(key instanceof Array)){
14950 handleKeyDown : function(e){
14951 if(this.enabled){ //just in case
14952 var b = this.bindings;
14953 for(var i = 0, len = b.length; i < len; i++){
14954 b[i].call(this, e);
14960 * Returns true if this KeyMap is enabled
14961 * @return {Boolean}
14963 isEnabled : function(){
14964 return this.enabled;
14968 * Enables this KeyMap
14970 enable: function(){
14972 this.el.on(this.eventName, this.handleKeyDown, this);
14973 this.enabled = true;
14978 * Disable this KeyMap
14980 disable: function(){
14982 this.el.removeListener(this.eventName, this.handleKeyDown, this);
14983 this.enabled = false;
14988 * Ext JS Library 1.1.1
14989 * Copyright(c) 2006-2007, Ext JS, LLC.
14991 * Originally Released Under LGPL - original licence link has changed is not relivant.
14994 * <script type="text/javascript">
14999 * @class Roo.util.TextMetrics
15000 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
15001 * wide, in pixels, a given block of text will be.
15004 Roo.util.TextMetrics = function(){
15008 * Measures the size of the specified text
15009 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
15010 * that can affect the size of the rendered text
15011 * @param {String} text The text to measure
15012 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
15013 * in order to accurately measure the text height
15014 * @return {Object} An object containing the text's size {width: (width), height: (height)}
15016 measure : function(el, text, fixedWidth){
15018 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
15021 shared.setFixedWidth(fixedWidth || 'auto');
15022 return shared.getSize(text);
15026 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
15027 * the overhead of multiple calls to initialize the style properties on each measurement.
15028 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
15029 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
15030 * in order to accurately measure the text height
15031 * @return {Roo.util.TextMetrics.Instance} instance The new instance
15033 createInstance : function(el, fixedWidth){
15034 return Roo.util.TextMetrics.Instance(el, fixedWidth);
15041 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
15042 var ml = new Roo.Element(document.createElement('div'));
15043 document.body.appendChild(ml.dom);
15044 ml.position('absolute');
15045 ml.setLeftTop(-1000, -1000);
15049 ml.setWidth(fixedWidth);
15054 * Returns the size of the specified text based on the internal element's style and width properties
15055 * @memberOf Roo.util.TextMetrics.Instance#
15056 * @param {String} text The text to measure
15057 * @return {Object} An object containing the text's size {width: (width), height: (height)}
15059 getSize : function(text){
15061 var s = ml.getSize();
15067 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
15068 * that can affect the size of the rendered text
15069 * @memberOf Roo.util.TextMetrics.Instance#
15070 * @param {String/HTMLElement} el The element, dom node or id
15072 bind : function(el){
15074 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
15079 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
15080 * to set a fixed width in order to accurately measure the text height.
15081 * @memberOf Roo.util.TextMetrics.Instance#
15082 * @param {Number} width The width to set on the element
15084 setFixedWidth : function(width){
15085 ml.setWidth(width);
15089 * Returns the measured width of the specified text
15090 * @memberOf Roo.util.TextMetrics.Instance#
15091 * @param {String} text The text to measure
15092 * @return {Number} width The width in pixels
15094 getWidth : function(text){
15095 ml.dom.style.width = 'auto';
15096 return this.getSize(text).width;
15100 * Returns the measured height of the specified text. For multiline text, be sure to call
15101 * {@link #setFixedWidth} if necessary.
15102 * @memberOf Roo.util.TextMetrics.Instance#
15103 * @param {String} text The text to measure
15104 * @return {Number} height The height in pixels
15106 getHeight : function(text){
15107 return this.getSize(text).height;
15111 instance.bind(bindTo);
15116 // backwards compat
15117 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
15119 * Ext JS Library 1.1.1
15120 * Copyright(c) 2006-2007, Ext JS, LLC.
15122 * Originally Released Under LGPL - original licence link has changed is not relivant.
15125 * <script type="text/javascript">
15129 * @class Roo.state.Provider
15130 * Abstract base class for state provider implementations. This class provides methods
15131 * for encoding and decoding <b>typed</b> variables including dates and defines the
15132 * Provider interface.
15134 Roo.state.Provider = function(){
15136 * @event statechange
15137 * Fires when a state change occurs.
15138 * @param {Provider} this This state provider
15139 * @param {String} key The state key which was changed
15140 * @param {String} value The encoded value for the state
15143 "statechange": true
15146 Roo.state.Provider.superclass.constructor.call(this);
15148 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
15150 * Returns the current value for a key
15151 * @param {String} name The key name
15152 * @param {Mixed} defaultValue A default value to return if the key's value is not found
15153 * @return {Mixed} The state data
15155 get : function(name, defaultValue){
15156 return typeof this.state[name] == "undefined" ?
15157 defaultValue : this.state[name];
15161 * Clears a value from the state
15162 * @param {String} name The key name
15164 clear : function(name){
15165 delete this.state[name];
15166 this.fireEvent("statechange", this, name, null);
15170 * Sets the value for a key
15171 * @param {String} name The key name
15172 * @param {Mixed} value The value to set
15174 set : function(name, value){
15175 this.state[name] = value;
15176 this.fireEvent("statechange", this, name, value);
15180 * Decodes a string previously encoded with {@link #encodeValue}.
15181 * @param {String} value The value to decode
15182 * @return {Mixed} The decoded value
15184 decodeValue : function(cookie){
15185 var re = /^(a|n|d|b|s|o)\:(.*)$/;
15186 var matches = re.exec(unescape(cookie));
15187 if(!matches || !matches[1]) {
15188 return; // non state cookie
15190 var type = matches[1];
15191 var v = matches[2];
15194 return parseFloat(v);
15196 return new Date(Date.parse(v));
15201 var values = v.split("^");
15202 for(var i = 0, len = values.length; i < len; i++){
15203 all.push(this.decodeValue(values[i]));
15208 var values = v.split("^");
15209 for(var i = 0, len = values.length; i < len; i++){
15210 var kv = values[i].split("=");
15211 all[kv[0]] = this.decodeValue(kv[1]);
15220 * Encodes a value including type information. Decode with {@link #decodeValue}.
15221 * @param {Mixed} value The value to encode
15222 * @return {String} The encoded value
15224 encodeValue : function(v){
15226 if(typeof v == "number"){
15228 }else if(typeof v == "boolean"){
15229 enc = "b:" + (v ? "1" : "0");
15230 }else if(v instanceof Date){
15231 enc = "d:" + v.toGMTString();
15232 }else if(v instanceof Array){
15234 for(var i = 0, len = v.length; i < len; i++){
15235 flat += this.encodeValue(v[i]);
15241 }else if(typeof v == "object"){
15244 if(typeof v[key] != "function"){
15245 flat += key + "=" + this.encodeValue(v[key]) + "^";
15248 enc = "o:" + flat.substring(0, flat.length-1);
15252 return escape(enc);
15258 * Ext JS Library 1.1.1
15259 * Copyright(c) 2006-2007, Ext JS, LLC.
15261 * Originally Released Under LGPL - original licence link has changed is not relivant.
15264 * <script type="text/javascript">
15267 * @class Roo.state.Manager
15268 * This is the global state manager. By default all components that are "state aware" check this class
15269 * for state information if you don't pass them a custom state provider. In order for this class
15270 * to be useful, it must be initialized with a provider when your application initializes.
15272 // in your initialization function
15274 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
15276 // supposed you have a {@link Roo.BorderLayout}
15277 var layout = new Roo.BorderLayout(...);
15278 layout.restoreState();
15279 // or a {Roo.BasicDialog}
15280 var dialog = new Roo.BasicDialog(...);
15281 dialog.restoreState();
15285 Roo.state.Manager = function(){
15286 var provider = new Roo.state.Provider();
15290 * Configures the default state provider for your application
15291 * @param {Provider} stateProvider The state provider to set
15293 setProvider : function(stateProvider){
15294 provider = stateProvider;
15298 * Returns the current value for a key
15299 * @param {String} name The key name
15300 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
15301 * @return {Mixed} The state data
15303 get : function(key, defaultValue){
15304 return provider.get(key, defaultValue);
15308 * Sets the value for a key
15309 * @param {String} name The key name
15310 * @param {Mixed} value The state data
15312 set : function(key, value){
15313 provider.set(key, value);
15317 * Clears a value from the state
15318 * @param {String} name The key name
15320 clear : function(key){
15321 provider.clear(key);
15325 * Gets the currently configured state provider
15326 * @return {Provider} The state provider
15328 getProvider : function(){
15335 * Ext JS Library 1.1.1
15336 * Copyright(c) 2006-2007, Ext JS, LLC.
15338 * Originally Released Under LGPL - original licence link has changed is not relivant.
15341 * <script type="text/javascript">
15344 * @class Roo.state.CookieProvider
15345 * @extends Roo.state.Provider
15346 * The default Provider implementation which saves state via cookies.
15349 var cp = new Roo.state.CookieProvider({
15351 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
15352 domain: "roojs.com"
15354 Roo.state.Manager.setProvider(cp);
15356 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
15357 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
15358 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
15359 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
15360 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
15361 * domain the page is running on including the 'www' like 'www.roojs.com')
15362 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
15364 * Create a new CookieProvider
15365 * @param {Object} config The configuration object
15367 Roo.state.CookieProvider = function(config){
15368 Roo.state.CookieProvider.superclass.constructor.call(this);
15370 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
15371 this.domain = null;
15372 this.secure = false;
15373 Roo.apply(this, config);
15374 this.state = this.readCookies();
15377 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
15379 set : function(name, value){
15380 if(typeof value == "undefined" || value === null){
15384 this.setCookie(name, value);
15385 Roo.state.CookieProvider.superclass.set.call(this, name, value);
15389 clear : function(name){
15390 this.clearCookie(name);
15391 Roo.state.CookieProvider.superclass.clear.call(this, name);
15395 readCookies : function(){
15397 var c = document.cookie + ";";
15398 var re = /\s?(.*?)=(.*?);/g;
15400 while((matches = re.exec(c)) != null){
15401 var name = matches[1];
15402 var value = matches[2];
15403 if(name && name.substring(0,3) == "ys-"){
15404 cookies[name.substr(3)] = this.decodeValue(value);
15411 setCookie : function(name, value){
15412 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
15413 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
15414 ((this.path == null) ? "" : ("; path=" + this.path)) +
15415 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15416 ((this.secure == true) ? "; secure" : "");
15420 clearCookie : function(name){
15421 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
15422 ((this.path == null) ? "" : ("; path=" + this.path)) +
15423 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15424 ((this.secure == true) ? "; secure" : "");
15428 * Ext JS Library 1.1.1
15429 * Copyright(c) 2006-2007, Ext JS, LLC.
15431 * Originally Released Under LGPL - original licence link has changed is not relivant.
15434 * <script type="text/javascript">
15439 * @class Roo.ComponentMgr
15440 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
15443 Roo.ComponentMgr = function(){
15444 var all = new Roo.util.MixedCollection();
15448 * Registers a component.
15449 * @param {Roo.Component} c The component
15451 register : function(c){
15456 * Unregisters a component.
15457 * @param {Roo.Component} c The component
15459 unregister : function(c){
15464 * Returns a component by id
15465 * @param {String} id The component id
15467 get : function(id){
15468 return all.get(id);
15472 * Registers a function that will be called when a specified component is added to ComponentMgr
15473 * @param {String} id The component id
15474 * @param {Funtction} fn The callback function
15475 * @param {Object} scope The scope of the callback
15477 onAvailable : function(id, fn, scope){
15478 all.on("add", function(index, o){
15480 fn.call(scope || o, o);
15481 all.un("add", fn, scope);
15488 * Ext JS Library 1.1.1
15489 * Copyright(c) 2006-2007, Ext JS, LLC.
15491 * Originally Released Under LGPL - original licence link has changed is not relivant.
15494 * <script type="text/javascript">
15498 * @class Roo.Component
15499 * @extends Roo.util.Observable
15500 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
15501 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
15502 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15503 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15504 * All visual components (widgets) that require rendering into a layout should subclass Component.
15506 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
15507 * 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
15508 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
15510 Roo.Component = function(config){
15511 config = config || {};
15512 if(config.tagName || config.dom || typeof config == "string"){ // element object
15513 config = {el: config, id: config.id || config};
15515 this.initialConfig = config;
15517 Roo.apply(this, config);
15521 * Fires after the component is disabled.
15522 * @param {Roo.Component} this
15527 * Fires after the component is enabled.
15528 * @param {Roo.Component} this
15532 * @event beforeshow
15533 * Fires before the component is shown. Return false to stop the show.
15534 * @param {Roo.Component} this
15539 * Fires after the component is shown.
15540 * @param {Roo.Component} this
15544 * @event beforehide
15545 * Fires before the component is hidden. Return false to stop the hide.
15546 * @param {Roo.Component} this
15551 * Fires after the component is hidden.
15552 * @param {Roo.Component} this
15556 * @event beforerender
15557 * Fires before the component is rendered. Return false to stop the render.
15558 * @param {Roo.Component} this
15560 beforerender : true,
15563 * Fires after the component is rendered.
15564 * @param {Roo.Component} this
15568 * @event beforedestroy
15569 * Fires before the component is destroyed. Return false to stop the destroy.
15570 * @param {Roo.Component} this
15572 beforedestroy : true,
15575 * Fires after the component is destroyed.
15576 * @param {Roo.Component} this
15581 this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
15583 Roo.ComponentMgr.register(this);
15584 Roo.Component.superclass.constructor.call(this);
15585 this.initComponent();
15586 if(this.renderTo){ // not supported by all components yet. use at your own risk!
15587 this.render(this.renderTo);
15588 delete this.renderTo;
15593 Roo.Component.AUTO_ID = 1000;
15595 Roo.extend(Roo.Component, Roo.util.Observable, {
15597 * @scope Roo.Component.prototype
15599 * true if this component is hidden. Read-only.
15604 * true if this component is disabled. Read-only.
15609 * true if this component has been rendered. Read-only.
15613 /** @cfg {String} disableClass
15614 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15616 disabledClass : "x-item-disabled",
15617 /** @cfg {Boolean} allowDomMove
15618 * Whether the component can move the Dom node when rendering (defaults to true).
15620 allowDomMove : true,
15621 /** @cfg {String} hideMode (display|visibility)
15622 * How this component should hidden. Supported values are
15623 * "visibility" (css visibility), "offsets" (negative offset position) and
15624 * "display" (css display) - defaults to "display".
15626 hideMode: 'display',
15629 ctype : "Roo.Component",
15632 * @cfg {String} actionMode
15633 * which property holds the element that used for hide() / show() / disable() / enable()
15634 * default is 'el' for forms you probably want to set this to fieldEl
15639 getActionEl : function(){
15640 return this[this.actionMode];
15643 initComponent : Roo.emptyFn,
15645 * If this is a lazy rendering component, render it to its container element.
15646 * @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.
15648 render : function(container, position){
15654 if(this.fireEvent("beforerender", this) === false){
15658 if(!container && this.el){
15659 this.el = Roo.get(this.el);
15660 container = this.el.dom.parentNode;
15661 this.allowDomMove = false;
15663 this.container = Roo.get(container);
15664 this.rendered = true;
15665 if(position !== undefined){
15666 if(typeof position == 'number'){
15667 position = this.container.dom.childNodes[position];
15669 position = Roo.getDom(position);
15672 this.onRender(this.container, position || null);
15674 this.el.addClass(this.cls);
15678 this.el.applyStyles(this.style);
15681 this.fireEvent("render", this);
15682 this.afterRender(this.container);
15695 // default function is not really useful
15696 onRender : function(ct, position){
15698 this.el = Roo.get(this.el);
15699 if(this.allowDomMove !== false){
15700 ct.dom.insertBefore(this.el.dom, position);
15706 getAutoCreate : function(){
15707 var cfg = typeof this.autoCreate == "object" ?
15708 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15709 if(this.id && !cfg.id){
15716 afterRender : Roo.emptyFn,
15719 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15720 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15722 destroy : function(){
15723 if(this.fireEvent("beforedestroy", this) !== false){
15724 this.purgeListeners();
15725 this.beforeDestroy();
15727 this.el.removeAllListeners();
15729 if(this.actionMode == "container"){
15730 this.container.remove();
15734 Roo.ComponentMgr.unregister(this);
15735 this.fireEvent("destroy", this);
15740 beforeDestroy : function(){
15745 onDestroy : function(){
15750 * Returns the underlying {@link Roo.Element}.
15751 * @return {Roo.Element} The element
15753 getEl : function(){
15758 * Returns the id of this component.
15761 getId : function(){
15766 * Try to focus this component.
15767 * @param {Boolean} selectText True to also select the text in this component (if applicable)
15768 * @return {Roo.Component} this
15770 focus : function(selectText){
15773 if(selectText === true){
15774 this.el.dom.select();
15789 * Disable this component.
15790 * @return {Roo.Component} this
15792 disable : function(){
15796 this.disabled = true;
15797 this.fireEvent("disable", this);
15802 onDisable : function(){
15803 this.getActionEl().addClass(this.disabledClass);
15804 this.el.dom.disabled = true;
15808 * Enable this component.
15809 * @return {Roo.Component} this
15811 enable : function(){
15815 this.disabled = false;
15816 this.fireEvent("enable", this);
15821 onEnable : function(){
15822 this.getActionEl().removeClass(this.disabledClass);
15823 this.el.dom.disabled = false;
15827 * Convenience function for setting disabled/enabled by boolean.
15828 * @param {Boolean} disabled
15830 setDisabled : function(disabled){
15831 this[disabled ? "disable" : "enable"]();
15835 * Show this component.
15836 * @return {Roo.Component} this
15839 if(this.fireEvent("beforeshow", this) !== false){
15840 this.hidden = false;
15844 this.fireEvent("show", this);
15850 onShow : function(){
15851 var ae = this.getActionEl();
15852 if(this.hideMode == 'visibility'){
15853 ae.dom.style.visibility = "visible";
15854 }else if(this.hideMode == 'offsets'){
15855 ae.removeClass('x-hidden');
15857 ae.dom.style.display = "";
15862 * Hide this component.
15863 * @return {Roo.Component} this
15866 if(this.fireEvent("beforehide", this) !== false){
15867 this.hidden = true;
15871 this.fireEvent("hide", this);
15877 onHide : function(){
15878 var ae = this.getActionEl();
15879 if(this.hideMode == 'visibility'){
15880 ae.dom.style.visibility = "hidden";
15881 }else if(this.hideMode == 'offsets'){
15882 ae.addClass('x-hidden');
15884 ae.dom.style.display = "none";
15889 * Convenience function to hide or show this component by boolean.
15890 * @param {Boolean} visible True to show, false to hide
15891 * @return {Roo.Component} this
15893 setVisible: function(visible){
15903 * Returns true if this component is visible.
15905 isVisible : function(){
15906 return this.getActionEl().isVisible();
15909 cloneConfig : function(overrides){
15910 overrides = overrides || {};
15911 var id = overrides.id || Roo.id();
15912 var cfg = Roo.applyIf(overrides, this.initialConfig);
15913 cfg.id = id; // prevent dup id
15914 return new this.constructor(cfg);
15918 * Ext JS Library 1.1.1
15919 * Copyright(c) 2006-2007, Ext JS, LLC.
15921 * Originally Released Under LGPL - original licence link has changed is not relivant.
15924 * <script type="text/javascript">
15928 * @class Roo.BoxComponent
15929 * @extends Roo.Component
15930 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
15931 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
15932 * container classes should subclass BoxComponent so that they will work consistently when nested within other Roo
15933 * layout containers.
15935 * @param {Roo.Element/String/Object} config The configuration options.
15937 Roo.BoxComponent = function(config){
15938 Roo.Component.call(this, config);
15942 * Fires after the component is resized.
15943 * @param {Roo.Component} this
15944 * @param {Number} adjWidth The box-adjusted width that was set
15945 * @param {Number} adjHeight The box-adjusted height that was set
15946 * @param {Number} rawWidth The width that was originally specified
15947 * @param {Number} rawHeight The height that was originally specified
15952 * Fires after the component is moved.
15953 * @param {Roo.Component} this
15954 * @param {Number} x The new x position
15955 * @param {Number} y The new y position
15961 Roo.extend(Roo.BoxComponent, Roo.Component, {
15962 // private, set in afterRender to signify that the component has been rendered
15964 // private, used to defer height settings to subclasses
15965 deferHeight: false,
15966 /** @cfg {Number} width
15967 * width (optional) size of component
15969 /** @cfg {Number} height
15970 * height (optional) size of component
15974 * Sets the width and height of the component. This method fires the resize event. This method can accept
15975 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15976 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15977 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15978 * @return {Roo.BoxComponent} this
15980 setSize : function(w, h){
15981 // support for standard size objects
15982 if(typeof w == 'object'){
15987 if(!this.boxReady){
15993 // prevent recalcs when not needed
15994 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15997 this.lastSize = {width: w, height: h};
15999 var adj = this.adjustSize(w, h);
16000 var aw = adj.width, ah = adj.height;
16001 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
16002 var rz = this.getResizeEl();
16003 if(!this.deferHeight && aw !== undefined && ah !== undefined){
16004 rz.setSize(aw, ah);
16005 }else if(!this.deferHeight && ah !== undefined){
16007 }else if(aw !== undefined){
16010 this.onResize(aw, ah, w, h);
16011 this.fireEvent('resize', this, aw, ah, w, h);
16017 * Gets the current size of the component's underlying element.
16018 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
16020 getSize : function(){
16021 return this.el.getSize();
16025 * Gets the current XY position of the component's underlying element.
16026 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
16027 * @return {Array} The XY position of the element (e.g., [100, 200])
16029 getPosition : function(local){
16030 if(local === true){
16031 return [this.el.getLeft(true), this.el.getTop(true)];
16033 return this.xy || this.el.getXY();
16037 * Gets the current box measurements of the component's underlying element.
16038 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
16039 * @returns {Object} box An object in the format {x, y, width, height}
16041 getBox : function(local){
16042 var s = this.el.getSize();
16044 s.x = this.el.getLeft(true);
16045 s.y = this.el.getTop(true);
16047 var xy = this.xy || this.el.getXY();
16055 * Sets the current box measurements of the component's underlying element.
16056 * @param {Object} box An object in the format {x, y, width, height}
16057 * @returns {Roo.BoxComponent} this
16059 updateBox : function(box){
16060 this.setSize(box.width, box.height);
16061 this.setPagePosition(box.x, box.y);
16066 getResizeEl : function(){
16067 return this.resizeEl || this.el;
16071 getPositionEl : function(){
16072 return this.positionEl || this.el;
16076 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
16077 * This method fires the move event.
16078 * @param {Number} left The new left
16079 * @param {Number} top The new top
16080 * @returns {Roo.BoxComponent} this
16082 setPosition : function(x, y){
16085 if(!this.boxReady){
16088 var adj = this.adjustPosition(x, y);
16089 var ax = adj.x, ay = adj.y;
16091 var el = this.getPositionEl();
16092 if(ax !== undefined || ay !== undefined){
16093 if(ax !== undefined && ay !== undefined){
16094 el.setLeftTop(ax, ay);
16095 }else if(ax !== undefined){
16097 }else if(ay !== undefined){
16100 this.onPosition(ax, ay);
16101 this.fireEvent('move', this, ax, ay);
16107 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
16108 * This method fires the move event.
16109 * @param {Number} x The new x position
16110 * @param {Number} y The new y position
16111 * @returns {Roo.BoxComponent} this
16113 setPagePosition : function(x, y){
16116 if(!this.boxReady){
16119 if(x === undefined || y === undefined){ // cannot translate undefined points
16122 var p = this.el.translatePoints(x, y);
16123 this.setPosition(p.left, p.top);
16128 onRender : function(ct, position){
16129 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
16131 this.resizeEl = Roo.get(this.resizeEl);
16133 if(this.positionEl){
16134 this.positionEl = Roo.get(this.positionEl);
16139 afterRender : function(){
16140 Roo.BoxComponent.superclass.afterRender.call(this);
16141 this.boxReady = true;
16142 this.setSize(this.width, this.height);
16143 if(this.x || this.y){
16144 this.setPosition(this.x, this.y);
16146 if(this.pageX || this.pageY){
16147 this.setPagePosition(this.pageX, this.pageY);
16152 * Force the component's size to recalculate based on the underlying element's current height and width.
16153 * @returns {Roo.BoxComponent} this
16155 syncSize : function(){
16156 delete this.lastSize;
16157 this.setSize(this.el.getWidth(), this.el.getHeight());
16162 * Called after the component is resized, this method is empty by default but can be implemented by any
16163 * subclass that needs to perform custom logic after a resize occurs.
16164 * @param {Number} adjWidth The box-adjusted width that was set
16165 * @param {Number} adjHeight The box-adjusted height that was set
16166 * @param {Number} rawWidth The width that was originally specified
16167 * @param {Number} rawHeight The height that was originally specified
16169 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
16174 * Called after the component is moved, this method is empty by default but can be implemented by any
16175 * subclass that needs to perform custom logic after a move occurs.
16176 * @param {Number} x The new x position
16177 * @param {Number} y The new y position
16179 onPosition : function(x, y){
16184 adjustSize : function(w, h){
16185 if(this.autoWidth){
16188 if(this.autoHeight){
16191 return {width : w, height: h};
16195 adjustPosition : function(x, y){
16196 return {x : x, y: y};
16200 * Ext JS Library 1.1.1
16201 * Copyright(c) 2006-2007, Ext JS, LLC.
16203 * Originally Released Under LGPL - original licence link has changed is not relivant.
16206 * <script type="text/javascript">
16211 * @extends Roo.Element
16212 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
16213 * automatic maintaining of shadow/shim positions.
16214 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
16215 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
16216 * you can pass a string with a CSS class name. False turns off the shadow.
16217 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
16218 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
16219 * @cfg {String} cls CSS class to add to the element
16220 * @cfg {Number} zindex Starting z-index (defaults to 11000)
16221 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
16223 * @param {Object} config An object with config options.
16224 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
16227 Roo.Layer = function(config, existingEl){
16228 config = config || {};
16229 var dh = Roo.DomHelper;
16230 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
16232 this.dom = Roo.getDom(existingEl);
16235 var o = config.dh || {tag: "div", cls: "x-layer"};
16236 this.dom = dh.append(pel, o);
16239 this.addClass(config.cls);
16241 this.constrain = config.constrain !== false;
16242 this.visibilityMode = Roo.Element.VISIBILITY;
16244 this.id = this.dom.id = config.id;
16246 this.id = Roo.id(this.dom);
16248 this.zindex = config.zindex || this.getZIndex();
16249 this.position("absolute", this.zindex);
16251 this.shadowOffset = config.shadowOffset || 4;
16252 this.shadow = new Roo.Shadow({
16253 offset : this.shadowOffset,
16254 mode : config.shadow
16257 this.shadowOffset = 0;
16259 this.useShim = config.shim !== false && Roo.useShims;
16260 this.useDisplay = config.useDisplay;
16264 var supr = Roo.Element.prototype;
16266 // shims are shared among layer to keep from having 100 iframes
16269 Roo.extend(Roo.Layer, Roo.Element, {
16271 getZIndex : function(){
16272 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
16275 getShim : function(){
16282 var shim = shims.shift();
16284 shim = this.createShim();
16285 shim.enableDisplayMode('block');
16286 shim.dom.style.display = 'none';
16287 shim.dom.style.visibility = 'visible';
16289 var pn = this.dom.parentNode;
16290 if(shim.dom.parentNode != pn){
16291 pn.insertBefore(shim.dom, this.dom);
16293 shim.setStyle('z-index', this.getZIndex()-2);
16298 hideShim : function(){
16300 this.shim.setDisplayed(false);
16301 shims.push(this.shim);
16306 disableShadow : function(){
16308 this.shadowDisabled = true;
16309 this.shadow.hide();
16310 this.lastShadowOffset = this.shadowOffset;
16311 this.shadowOffset = 0;
16315 enableShadow : function(show){
16317 this.shadowDisabled = false;
16318 this.shadowOffset = this.lastShadowOffset;
16319 delete this.lastShadowOffset;
16327 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
16328 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
16329 sync : function(doShow){
16330 var sw = this.shadow;
16331 if(!this.updating && this.isVisible() && (sw || this.useShim)){
16332 var sh = this.getShim();
16334 var w = this.getWidth(),
16335 h = this.getHeight();
16337 var l = this.getLeft(true),
16338 t = this.getTop(true);
16340 if(sw && !this.shadowDisabled){
16341 if(doShow && !sw.isVisible()){
16344 sw.realign(l, t, w, h);
16350 // fit the shim behind the shadow, so it is shimmed too
16351 var a = sw.adjusts, s = sh.dom.style;
16352 s.left = (Math.min(l, l+a.l))+"px";
16353 s.top = (Math.min(t, t+a.t))+"px";
16354 s.width = (w+a.w)+"px";
16355 s.height = (h+a.h)+"px";
16362 sh.setLeftTop(l, t);
16369 destroy : function(){
16372 this.shadow.hide();
16374 this.removeAllListeners();
16375 var pn = this.dom.parentNode;
16377 pn.removeChild(this.dom);
16379 Roo.Element.uncache(this.id);
16382 remove : function(){
16387 beginUpdate : function(){
16388 this.updating = true;
16392 endUpdate : function(){
16393 this.updating = false;
16398 hideUnders : function(negOffset){
16400 this.shadow.hide();
16406 constrainXY : function(){
16407 if(this.constrain){
16408 var vw = Roo.lib.Dom.getViewWidth(),
16409 vh = Roo.lib.Dom.getViewHeight();
16410 var s = Roo.get(document).getScroll();
16412 var xy = this.getXY();
16413 var x = xy[0], y = xy[1];
16414 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
16415 // only move it if it needs it
16417 // first validate right/bottom
16418 if((x + w) > vw+s.left){
16419 x = vw - w - this.shadowOffset;
16422 if((y + h) > vh+s.top){
16423 y = vh - h - this.shadowOffset;
16426 // then make sure top/left isn't negative
16437 var ay = this.avoidY;
16438 if(y <= ay && (y+h) >= ay){
16444 supr.setXY.call(this, xy);
16450 isVisible : function(){
16451 return this.visible;
16455 showAction : function(){
16456 this.visible = true; // track visibility to prevent getStyle calls
16457 if(this.useDisplay === true){
16458 this.setDisplayed("");
16459 }else if(this.lastXY){
16460 supr.setXY.call(this, this.lastXY);
16461 }else if(this.lastLT){
16462 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
16467 hideAction : function(){
16468 this.visible = false;
16469 if(this.useDisplay === true){
16470 this.setDisplayed(false);
16472 this.setLeftTop(-10000,-10000);
16476 // overridden Element method
16477 setVisible : function(v, a, d, c, e){
16482 var cb = function(){
16487 }.createDelegate(this);
16488 supr.setVisible.call(this, true, true, d, cb, e);
16491 this.hideUnders(true);
16500 }.createDelegate(this);
16502 supr.setVisible.call(this, v, a, d, cb, e);
16511 storeXY : function(xy){
16512 delete this.lastLT;
16516 storeLeftTop : function(left, top){
16517 delete this.lastXY;
16518 this.lastLT = [left, top];
16522 beforeFx : function(){
16523 this.beforeAction();
16524 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
16528 afterFx : function(){
16529 Roo.Layer.superclass.afterFx.apply(this, arguments);
16530 this.sync(this.isVisible());
16534 beforeAction : function(){
16535 if(!this.updating && this.shadow){
16536 this.shadow.hide();
16540 // overridden Element method
16541 setLeft : function(left){
16542 this.storeLeftTop(left, this.getTop(true));
16543 supr.setLeft.apply(this, arguments);
16547 setTop : function(top){
16548 this.storeLeftTop(this.getLeft(true), top);
16549 supr.setTop.apply(this, arguments);
16553 setLeftTop : function(left, top){
16554 this.storeLeftTop(left, top);
16555 supr.setLeftTop.apply(this, arguments);
16559 setXY : function(xy, a, d, c, e){
16561 this.beforeAction();
16563 var cb = this.createCB(c);
16564 supr.setXY.call(this, xy, a, d, cb, e);
16571 createCB : function(c){
16582 // overridden Element method
16583 setX : function(x, a, d, c, e){
16584 this.setXY([x, this.getY()], a, d, c, e);
16587 // overridden Element method
16588 setY : function(y, a, d, c, e){
16589 this.setXY([this.getX(), y], a, d, c, e);
16592 // overridden Element method
16593 setSize : function(w, h, a, d, c, e){
16594 this.beforeAction();
16595 var cb = this.createCB(c);
16596 supr.setSize.call(this, w, h, a, d, cb, e);
16602 // overridden Element method
16603 setWidth : function(w, a, d, c, e){
16604 this.beforeAction();
16605 var cb = this.createCB(c);
16606 supr.setWidth.call(this, w, a, d, cb, e);
16612 // overridden Element method
16613 setHeight : function(h, a, d, c, e){
16614 this.beforeAction();
16615 var cb = this.createCB(c);
16616 supr.setHeight.call(this, h, a, d, cb, e);
16622 // overridden Element method
16623 setBounds : function(x, y, w, h, a, d, c, e){
16624 this.beforeAction();
16625 var cb = this.createCB(c);
16627 this.storeXY([x, y]);
16628 supr.setXY.call(this, [x, y]);
16629 supr.setSize.call(this, w, h, a, d, cb, e);
16632 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
16638 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
16639 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
16640 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
16641 * @param {Number} zindex The new z-index to set
16642 * @return {this} The Layer
16644 setZIndex : function(zindex){
16645 this.zindex = zindex;
16646 this.setStyle("z-index", zindex + 2);
16648 this.shadow.setZIndex(zindex + 1);
16651 this.shim.setStyle("z-index", zindex);
16656 * Original code for Roojs - LGPL
16657 * <script type="text/javascript">
16661 * @class Roo.XComponent
16662 * A delayed Element creator...
16663 * Or a way to group chunks of interface together.
16664 * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
16665 * used in conjunction with XComponent.build() it will create an instance of each element,
16666 * then call addxtype() to build the User interface.
16668 * Mypart.xyx = new Roo.XComponent({
16670 parent : 'Mypart.xyz', // empty == document.element.!!
16674 disabled : function() {}
16676 tree : function() { // return an tree of xtype declared components
16680 xtype : 'NestedLayoutPanel',
16687 * It can be used to build a big heiracy, with parent etc.
16688 * or you can just use this to render a single compoent to a dom element
16689 * MYPART.render(Roo.Element | String(id) | dom_element )
16696 * Roo is designed primarily as a single page application, so the UI build for a standard interface will
16697 * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
16699 * Each sub module is expected to have a parent pointing to the class name of it's parent module.
16701 * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
16702 * - if mulitple topModules exist, the last one is defined as the top module.
16706 * When the top level or multiple modules are to embedded into a existing HTML page,
16707 * the parent element can container '#id' of the element where the module will be drawn.
16711 * Unlike classic Roo, the bootstrap tends not to be used as a single page.
16712 * it relies more on a include mechanism, where sub modules are included into an outer page.
16713 * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
16715 * Bootstrap Roo Included elements
16717 * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
16718 * hence confusing the component builder as it thinks there are multiple top level elements.
16720 * String Over-ride & Translations
16722 * Our builder application writes all the strings as _strings and _named_strings. This is to enable the translation of elements,
16723 * and also the 'overlaying of string values - needed when different versions of the same application with different text content
16724 * are needed. @see Roo.XComponent.overlayString
16728 * @extends Roo.util.Observable
16730 * @param cfg {Object} configuration of component
16733 Roo.XComponent = function(cfg) {
16734 Roo.apply(this, cfg);
16738 * Fires when this the componnt is built
16739 * @param {Roo.XComponent} c the component
16744 this.region = this.region || 'center'; // default..
16745 Roo.XComponent.register(this);
16746 this.modules = false;
16747 this.el = false; // where the layout goes..
16751 Roo.extend(Roo.XComponent, Roo.util.Observable, {
16754 * The created element (with Roo.factory())
16755 * @type {Roo.Layout}
16761 * for BC - use el in new code
16762 * @type {Roo.Layout}
16768 * for BC - use el in new code
16769 * @type {Roo.Layout}
16774 * @cfg {Function|boolean} disabled
16775 * If this module is disabled by some rule, return true from the funtion
16780 * @cfg {String} parent
16781 * Name of parent element which it get xtype added to..
16786 * @cfg {String} order
16787 * Used to set the order in which elements are created (usefull for multiple tabs)
16792 * @cfg {String} name
16793 * String to display while loading.
16797 * @cfg {String} region
16798 * Region to render component to (defaults to center)
16803 * @cfg {Array} items
16804 * A single item array - the first element is the root of the tree..
16805 * It's done this way to stay compatible with the Xtype system...
16811 * The method that retuns the tree of parts that make up this compoennt
16818 * render element to dom or tree
16819 * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
16822 render : function(el)
16826 var hp = this.parent ? 1 : 0;
16827 Roo.debug && Roo.log(this);
16829 var tree = this._tree ? this._tree() : this.tree();
16832 if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
16833 // if parent is a '#.....' string, then let's use that..
16834 var ename = this.parent.substr(1);
16835 this.parent = false;
16836 Roo.debug && Roo.log(ename);
16838 case 'bootstrap-body':
16839 if (typeof(tree.el) != 'undefined' && tree.el == document.body) {
16840 // this is the BorderLayout standard?
16841 this.parent = { el : true };
16844 if (["Nest", "Content", "Grid", "Tree"].indexOf(tree.xtype) > -1) {
16845 // need to insert stuff...
16847 el : new Roo.bootstrap.layout.Border({
16848 el : document.body,
16854 tabPosition: 'top',
16855 //resizeTabs: true,
16856 alwaysShowTabs: true,
16866 if (typeof(Roo.bootstrap.Body) != 'undefined' ) {
16867 this.parent = { el : new Roo.bootstrap.Body() };
16868 Roo.debug && Roo.log("setting el to doc body");
16871 throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
16875 this.parent = { el : true};
16878 el = Roo.get(ename);
16879 if (typeof(Roo.bootstrap) != 'undefined' && tree['|xns'] == 'Roo.bootstrap') {
16880 this.parent = { el : true};
16887 if (!el && !this.parent) {
16888 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
16893 Roo.debug && Roo.log("EL:");
16894 Roo.debug && Roo.log(el);
16895 Roo.debug && Roo.log("this.parent.el:");
16896 Roo.debug && Roo.log(this.parent.el);
16899 // altertive root elements ??? - we need a better way to indicate these.
16900 var is_alt = Roo.XComponent.is_alt ||
16901 (typeof(tree.el) != 'undefined' && tree.el == document.body) ||
16902 (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
16903 (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
16907 if (!this.parent && is_alt) {
16908 //el = Roo.get(document.body);
16909 this.parent = { el : true };
16914 if (!this.parent) {
16916 Roo.debug && Roo.log("no parent - creating one");
16918 el = el ? Roo.get(el) : false;
16920 if (typeof(Roo.BorderLayout) == 'undefined' ) {
16923 el : new Roo.bootstrap.layout.Border({
16924 el: el || document.body,
16930 tabPosition: 'top',
16931 //resizeTabs: true,
16932 alwaysShowTabs: false,
16935 overflow: 'visible'
16941 // it's a top level one..
16943 el : new Roo.BorderLayout(el || document.body, {
16948 tabPosition: 'top',
16949 //resizeTabs: true,
16950 alwaysShowTabs: el && hp? false : true,
16951 hideTabs: el || !hp ? true : false,
16959 if (!this.parent.el) {
16960 // probably an old style ctor, which has been disabled.
16964 // The 'tree' method is '_tree now'
16966 tree.region = tree.region || this.region;
16967 var is_body = false;
16968 if (this.parent.el === true) {
16969 // bootstrap... - body..
16973 this.parent.el = Roo.factory(tree);
16977 this.el = this.parent.el.addxtype(tree, undefined, is_body);
16978 this.fireEvent('built', this);
16980 this.panel = this.el;
16981 this.layout = this.panel.layout;
16982 this.parentLayout = this.parent.layout || false;
16988 Roo.apply(Roo.XComponent, {
16990 * @property hideProgress
16991 * true to disable the building progress bar.. usefull on single page renders.
16994 hideProgress : false,
16996 * @property buildCompleted
16997 * True when the builder has completed building the interface.
17000 buildCompleted : false,
17003 * @property topModule
17004 * the upper most module - uses document.element as it's constructor.
17011 * @property modules
17012 * array of modules to be created by registration system.
17013 * @type {Array} of Roo.XComponent
17018 * @property elmodules
17019 * array of modules to be created by which use #ID
17020 * @type {Array} of Roo.XComponent
17027 * Is an alternative Root - normally used by bootstrap or other systems,
17028 * where the top element in the tree can wrap 'body'
17029 * @type {boolean} (default false)
17034 * @property build_from_html
17035 * Build elements from html - used by bootstrap HTML stuff
17036 * - this is cleared after build is completed
17037 * @type {boolean} (default false)
17040 build_from_html : false,
17042 * Register components to be built later.
17044 * This solves the following issues
17045 * - Building is not done on page load, but after an authentication process has occured.
17046 * - Interface elements are registered on page load
17047 * - Parent Interface elements may not be loaded before child, so this handles that..
17054 module : 'Pman.Tab.projectMgr',
17056 parent : 'Pman.layout',
17057 disabled : false, // or use a function..
17060 * * @param {Object} details about module
17062 register : function(obj) {
17064 Roo.XComponent.event.fireEvent('register', obj);
17065 switch(typeof(obj.disabled) ) {
17071 if ( obj.disabled() ) {
17077 if (obj.disabled || obj.region == '#disabled') {
17083 this.modules.push(obj);
17087 * convert a string to an object..
17088 * eg. 'AAA.BBB' -> finds AAA.BBB
17092 toObject : function(str)
17094 if (!str || typeof(str) == 'object') {
17097 if (str.substring(0,1) == '#') {
17101 var ar = str.split('.');
17106 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
17108 throw "Module not found : " + str;
17112 throw "Module not found : " + str;
17114 Roo.each(ar, function(e) {
17115 if (typeof(o[e]) == 'undefined') {
17116 throw "Module not found : " + str;
17127 * move modules into their correct place in the tree..
17130 preBuild : function ()
17133 Roo.each(this.modules , function (obj)
17135 Roo.XComponent.event.fireEvent('beforebuild', obj);
17137 var opar = obj.parent;
17139 obj.parent = this.toObject(opar);
17141 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
17146 Roo.debug && Roo.log("GOT top level module");
17147 Roo.debug && Roo.log(obj);
17148 obj.modules = new Roo.util.MixedCollection(false,
17149 function(o) { return o.order + '' }
17151 this.topModule = obj;
17154 // parent is a string (usually a dom element name..)
17155 if (typeof(obj.parent) == 'string') {
17156 this.elmodules.push(obj);
17159 if (obj.parent.constructor != Roo.XComponent) {
17160 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
17162 if (!obj.parent.modules) {
17163 obj.parent.modules = new Roo.util.MixedCollection(false,
17164 function(o) { return o.order + '' }
17167 if (obj.parent.disabled) {
17168 obj.disabled = true;
17170 obj.parent.modules.add(obj);
17175 * make a list of modules to build.
17176 * @return {Array} list of modules.
17179 buildOrder : function()
17182 var cmp = function(a,b) {
17183 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
17185 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
17186 throw "No top level modules to build";
17189 // make a flat list in order of modules to build.
17190 var mods = this.topModule ? [ this.topModule ] : [];
17193 // elmodules (is a list of DOM based modules )
17194 Roo.each(this.elmodules, function(e) {
17196 if (!this.topModule &&
17197 typeof(e.parent) == 'string' &&
17198 e.parent.substring(0,1) == '#' &&
17199 Roo.get(e.parent.substr(1))
17202 _this.topModule = e;
17208 // add modules to their parents..
17209 var addMod = function(m) {
17210 Roo.debug && Roo.log("build Order: add: " + m.name);
17213 if (m.modules && !m.disabled) {
17214 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
17215 m.modules.keySort('ASC', cmp );
17216 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
17218 m.modules.each(addMod);
17220 Roo.debug && Roo.log("build Order: no child modules");
17222 // not sure if this is used any more..
17224 m.finalize.name = m.name + " (clean up) ";
17225 mods.push(m.finalize);
17229 if (this.topModule && this.topModule.modules) {
17230 this.topModule.modules.keySort('ASC', cmp );
17231 this.topModule.modules.each(addMod);
17237 * Build the registered modules.
17238 * @param {Object} parent element.
17239 * @param {Function} optional method to call after module has been added.
17243 build : function(opts)
17246 if (typeof(opts) != 'undefined') {
17247 Roo.apply(this,opts);
17251 var mods = this.buildOrder();
17253 //this.allmods = mods;
17254 //Roo.debug && Roo.log(mods);
17256 if (!mods.length) { // should not happen
17257 throw "NO modules!!!";
17261 var msg = "Building Interface...";
17262 // flash it up as modal - so we store the mask!?
17263 if (!this.hideProgress && Roo.MessageBox) {
17264 Roo.MessageBox.show({ title: 'loading' });
17265 Roo.MessageBox.show({
17266 title: "Please wait...",
17276 var total = mods.length;
17279 var progressRun = function() {
17280 if (!mods.length) {
17281 Roo.debug && Roo.log('hide?');
17282 if (!this.hideProgress && Roo.MessageBox) {
17283 Roo.MessageBox.hide();
17285 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
17287 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
17293 var m = mods.shift();
17296 Roo.debug && Roo.log(m);
17297 // not sure if this is supported any more.. - modules that are are just function
17298 if (typeof(m) == 'function') {
17300 return progressRun.defer(10, _this);
17304 msg = "Building Interface " + (total - mods.length) +
17306 (m.name ? (' - ' + m.name) : '');
17307 Roo.debug && Roo.log(msg);
17308 if (!_this.hideProgress && Roo.MessageBox) {
17309 Roo.MessageBox.updateProgress( (total - mods.length)/total, msg );
17313 // is the module disabled?
17314 var disabled = (typeof(m.disabled) == 'function') ?
17315 m.disabled.call(m.module.disabled) : m.disabled;
17319 return progressRun(); // we do not update the display!
17327 // it's 10 on top level, and 1 on others??? why...
17328 return progressRun.defer(10, _this);
17331 progressRun.defer(1, _this);
17337 * Overlay a set of modified strings onto a component
17338 * This is dependant on our builder exporting the strings and 'named strings' elements.
17340 * @param {Object} element to overlay on - eg. Pman.Dialog.Login
17341 * @param {Object} associative array of 'named' string and it's new value.
17344 overlayStrings : function( component, strings )
17346 if (typeof(component['_named_strings']) == 'undefined') {
17347 throw "ERROR: component does not have _named_strings";
17349 for ( var k in strings ) {
17350 var md = typeof(component['_named_strings'][k]) == 'undefined' ? false : component['_named_strings'][k];
17351 if (md !== false) {
17352 component['_strings'][md] = strings[k];
17354 Roo.log('could not find named string: ' + k + ' in');
17355 Roo.log(component);
17370 * wrapper for event.on - aliased later..
17371 * Typically use to register a event handler for register:
17373 * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
17382 Roo.XComponent.event = new Roo.util.Observable({
17386 * Fires when an Component is registered,
17387 * set the disable property on the Component to stop registration.
17388 * @param {Roo.XComponent} c the component being registerd.
17393 * @event beforebuild
17394 * Fires before each Component is built
17395 * can be used to apply permissions.
17396 * @param {Roo.XComponent} c the component being registerd.
17399 'beforebuild' : true,
17401 * @event buildcomplete
17402 * Fires on the top level element when all elements have been built
17403 * @param {Roo.XComponent} the top level component.
17405 'buildcomplete' : true
17410 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event);
17413 * marked - a markdown parser
17414 * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
17415 * https://github.com/chjj/marked
17421 * Roo.Markdown - is a very crude wrapper around marked..
17425 * alert( Roo.Markdown.toHtml("Markdown *rocks*.") );
17427 * Note: move the sample code to the bottom of this
17428 * file before uncommenting it.
17433 Roo.Markdown.toHtml = function(text) {
17435 var c = new Roo.Markdown.marked.setOptions({
17436 renderer: new Roo.Markdown.marked.Renderer(),
17447 text = text.replace(/\\\n/g,' ');
17448 return Roo.Markdown.marked(text);
17453 // Wraps all "globals" so that the only thing
17454 // exposed is makeHtml().
17460 * eval:var:unescape
17468 var escape = function (html, encode) {
17470 .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&')
17471 .replace(/</g, '<')
17472 .replace(/>/g, '>')
17473 .replace(/"/g, '"')
17474 .replace(/'/g, ''');
17477 var unescape = function (html) {
17478 // explicitly match decimal, hex, and named HTML entities
17479 return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
17480 n = n.toLowerCase();
17481 if (n === 'colon') { return ':'; }
17482 if (n.charAt(0) === '#') {
17483 return n.charAt(1) === 'x'
17484 ? String.fromCharCode(parseInt(n.substring(2), 16))
17485 : String.fromCharCode(+n.substring(1));
17491 var replace = function (regex, opt) {
17492 regex = regex.source;
17494 return function self(name, val) {
17495 if (!name) { return new RegExp(regex, opt); }
17496 val = val.source || val;
17497 val = val.replace(/(^|[^\[])\^/g, '$1');
17498 regex = regex.replace(name, val);
17507 var noop = function () {}
17513 var merge = function (obj) {
17518 for (; i < arguments.length; i++) {
17519 target = arguments[i];
17520 for (key in target) {
17521 if (Object.prototype.hasOwnProperty.call(target, key)) {
17522 obj[key] = target[key];
17532 * Block-Level Grammar
17540 code: /^( {4}[^\n]+\n*)+/,
17542 hr: /^( *[-*_]){3,} *(?:\n+|$)/,
17543 heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
17545 lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
17546 blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
17547 list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
17548 html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
17549 def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
17551 paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
17555 block.bullet = /(?:[*+-]|\d+\.)/;
17556 block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
17557 block.item = replace(block.item, 'gm')
17558 (/bull/g, block.bullet)
17561 block.list = replace(block.list)
17562 (/bull/g, block.bullet)
17563 ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
17564 ('def', '\\n+(?=' + block.def.source + ')')
17567 block.blockquote = replace(block.blockquote)
17571 block._tag = '(?!(?:'
17572 + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
17573 + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
17574 + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
17576 block.html = replace(block.html)
17577 ('comment', /<!--[\s\S]*?-->/)
17578 ('closed', /<(tag)[\s\S]+?<\/\1>/)
17579 ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
17580 (/tag/g, block._tag)
17583 block.paragraph = replace(block.paragraph)
17585 ('heading', block.heading)
17586 ('lheading', block.lheading)
17587 ('blockquote', block.blockquote)
17588 ('tag', '<' + block._tag)
17593 * Normal Block Grammar
17596 block.normal = merge({}, block);
17599 * GFM Block Grammar
17602 block.gfm = merge({}, block.normal, {
17603 fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,
17605 heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
17608 block.gfm.paragraph = replace(block.paragraph)
17610 + block.gfm.fences.source.replace('\\1', '\\2') + '|'
17611 + block.list.source.replace('\\1', '\\3') + '|')
17615 * GFM + Tables Block Grammar
17618 block.tables = merge({}, block.gfm, {
17619 nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
17620 table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
17627 var Lexer = function (options) {
17629 this.tokens.links = {};
17630 this.options = options || marked.defaults;
17631 this.rules = block.normal;
17633 if (this.options.gfm) {
17634 if (this.options.tables) {
17635 this.rules = block.tables;
17637 this.rules = block.gfm;
17643 * Expose Block Rules
17646 Lexer.rules = block;
17649 * Static Lex Method
17652 Lexer.lex = function(src, options) {
17653 var lexer = new Lexer(options);
17654 return lexer.lex(src);
17661 Lexer.prototype.lex = function(src) {
17663 .replace(/\r\n|\r/g, '\n')
17664 .replace(/\t/g, ' ')
17665 .replace(/\u00a0/g, ' ')
17666 .replace(/\u2424/g, '\n');
17668 return this.token(src, true);
17675 Lexer.prototype.token = function(src, top, bq) {
17676 var src = src.replace(/^ +$/gm, '')
17689 if (cap = this.rules.newline.exec(src)) {
17690 src = src.substring(cap[0].length);
17691 if (cap[0].length > 1) {
17699 if (cap = this.rules.code.exec(src)) {
17700 src = src.substring(cap[0].length);
17701 cap = cap[0].replace(/^ {4}/gm, '');
17704 text: !this.options.pedantic
17705 ? cap.replace(/\n+$/, '')
17712 if (cap = this.rules.fences.exec(src)) {
17713 src = src.substring(cap[0].length);
17723 if (cap = this.rules.heading.exec(src)) {
17724 src = src.substring(cap[0].length);
17727 depth: cap[1].length,
17733 // table no leading pipe (gfm)
17734 if (top && (cap = this.rules.nptable.exec(src))) {
17735 src = src.substring(cap[0].length);
17739 header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
17740 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
17741 cells: cap[3].replace(/\n$/, '').split('\n')
17744 for (i = 0; i < item.align.length; i++) {
17745 if (/^ *-+: *$/.test(item.align[i])) {
17746 item.align[i] = 'right';
17747 } else if (/^ *:-+: *$/.test(item.align[i])) {
17748 item.align[i] = 'center';
17749 } else if (/^ *:-+ *$/.test(item.align[i])) {
17750 item.align[i] = 'left';
17752 item.align[i] = null;
17756 for (i = 0; i < item.cells.length; i++) {
17757 item.cells[i] = item.cells[i].split(/ *\| */);
17760 this.tokens.push(item);
17766 if (cap = this.rules.lheading.exec(src)) {
17767 src = src.substring(cap[0].length);
17770 depth: cap[2] === '=' ? 1 : 2,
17777 if (cap = this.rules.hr.exec(src)) {
17778 src = src.substring(cap[0].length);
17786 if (cap = this.rules.blockquote.exec(src)) {
17787 src = src.substring(cap[0].length);
17790 type: 'blockquote_start'
17793 cap = cap[0].replace(/^ *> ?/gm, '');
17795 // Pass `top` to keep the current
17796 // "toplevel" state. This is exactly
17797 // how markdown.pl works.
17798 this.token(cap, top, true);
17801 type: 'blockquote_end'
17808 if (cap = this.rules.list.exec(src)) {
17809 src = src.substring(cap[0].length);
17813 type: 'list_start',
17814 ordered: bull.length > 1
17817 // Get each top-level item.
17818 cap = cap[0].match(this.rules.item);
17824 for (; i < l; i++) {
17827 // Remove the list item's bullet
17828 // so it is seen as the next token.
17829 space = item.length;
17830 item = item.replace(/^ *([*+-]|\d+\.) +/, '');
17832 // Outdent whatever the
17833 // list item contains. Hacky.
17834 if (~item.indexOf('\n ')) {
17835 space -= item.length;
17836 item = !this.options.pedantic
17837 ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
17838 : item.replace(/^ {1,4}/gm, '');
17841 // Determine whether the next list item belongs here.
17842 // Backpedal if it does not belong in this list.
17843 if (this.options.smartLists && i !== l - 1) {
17844 b = block.bullet.exec(cap[i + 1])[0];
17845 if (bull !== b && !(bull.length > 1 && b.length > 1)) {
17846 src = cap.slice(i + 1).join('\n') + src;
17851 // Determine whether item is loose or not.
17852 // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
17853 // for discount behavior.
17854 loose = next || /\n\n(?!\s*$)/.test(item);
17856 next = item.charAt(item.length - 1) === '\n';
17857 if (!loose) { loose = next; }
17862 ? 'loose_item_start'
17863 : 'list_item_start'
17867 this.token(item, false, bq);
17870 type: 'list_item_end'
17882 if (cap = this.rules.html.exec(src)) {
17883 src = src.substring(cap[0].length);
17885 type: this.options.sanitize
17888 pre: !this.options.sanitizer
17889 && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
17896 if ((!bq && top) && (cap = this.rules.def.exec(src))) {
17897 src = src.substring(cap[0].length);
17898 this.tokens.links[cap[1].toLowerCase()] = {
17906 if (top && (cap = this.rules.table.exec(src))) {
17907 src = src.substring(cap[0].length);
17911 header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
17912 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
17913 cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
17916 for (i = 0; i < item.align.length; i++) {
17917 if (/^ *-+: *$/.test(item.align[i])) {
17918 item.align[i] = 'right';
17919 } else if (/^ *:-+: *$/.test(item.align[i])) {
17920 item.align[i] = 'center';
17921 } else if (/^ *:-+ *$/.test(item.align[i])) {
17922 item.align[i] = 'left';
17924 item.align[i] = null;
17928 for (i = 0; i < item.cells.length; i++) {
17929 item.cells[i] = item.cells[i]
17930 .replace(/^ *\| *| *\| *$/g, '')
17934 this.tokens.push(item);
17939 // top-level paragraph
17940 if (top && (cap = this.rules.paragraph.exec(src))) {
17941 src = src.substring(cap[0].length);
17944 text: cap[1].charAt(cap[1].length - 1) === '\n'
17945 ? cap[1].slice(0, -1)
17952 if (cap = this.rules.text.exec(src)) {
17953 // Top-level should never reach here.
17954 src = src.substring(cap[0].length);
17964 Error('Infinite loop on byte: ' + src.charCodeAt(0));
17968 return this.tokens;
17972 * Inline-Level Grammar
17976 escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
17977 autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
17979 tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
17980 link: /^!?\[(inside)\]\(href\)/,
17981 reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
17982 nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
17983 strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
17984 em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
17985 code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
17986 br: /^ {2,}\n(?!\s*$)/,
17988 text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
17991 inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
17992 inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
17994 inline.link = replace(inline.link)
17995 ('inside', inline._inside)
17996 ('href', inline._href)
17999 inline.reflink = replace(inline.reflink)
18000 ('inside', inline._inside)
18004 * Normal Inline Grammar
18007 inline.normal = merge({}, inline);
18010 * Pedantic Inline Grammar
18013 inline.pedantic = merge({}, inline.normal, {
18014 strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
18015 em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
18019 * GFM Inline Grammar
18022 inline.gfm = merge({}, inline.normal, {
18023 escape: replace(inline.escape)('])', '~|])')(),
18024 url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
18025 del: /^~~(?=\S)([\s\S]*?\S)~~/,
18026 text: replace(inline.text)
18028 ('|', '|https?://|')
18033 * GFM + Line Breaks Inline Grammar
18036 inline.breaks = merge({}, inline.gfm, {
18037 br: replace(inline.br)('{2,}', '*')(),
18038 text: replace(inline.gfm.text)('{2,}', '*')()
18042 * Inline Lexer & Compiler
18045 var InlineLexer = function (links, options) {
18046 this.options = options || marked.defaults;
18047 this.links = links;
18048 this.rules = inline.normal;
18049 this.renderer = this.options.renderer || new Renderer;
18050 this.renderer.options = this.options;
18054 Error('Tokens array requires a `links` property.');
18057 if (this.options.gfm) {
18058 if (this.options.breaks) {
18059 this.rules = inline.breaks;
18061 this.rules = inline.gfm;
18063 } else if (this.options.pedantic) {
18064 this.rules = inline.pedantic;
18069 * Expose Inline Rules
18072 InlineLexer.rules = inline;
18075 * Static Lexing/Compiling Method
18078 InlineLexer.output = function(src, links, options) {
18079 var inline = new InlineLexer(links, options);
18080 return inline.output(src);
18087 InlineLexer.prototype.output = function(src) {
18096 if (cap = this.rules.escape.exec(src)) {
18097 src = src.substring(cap[0].length);
18103 if (cap = this.rules.autolink.exec(src)) {
18104 src = src.substring(cap[0].length);
18105 if (cap[2] === '@') {
18106 text = cap[1].charAt(6) === ':'
18107 ? this.mangle(cap[1].substring(7))
18108 : this.mangle(cap[1]);
18109 href = this.mangle('mailto:') + text;
18111 text = escape(cap[1]);
18114 out += this.renderer.link(href, null, text);
18119 if (!this.inLink && (cap = this.rules.url.exec(src))) {
18120 src = src.substring(cap[0].length);
18121 text = escape(cap[1]);
18123 out += this.renderer.link(href, null, text);
18128 if (cap = this.rules.tag.exec(src)) {
18129 if (!this.inLink && /^<a /i.test(cap[0])) {
18130 this.inLink = true;
18131 } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
18132 this.inLink = false;
18134 src = src.substring(cap[0].length);
18135 out += this.options.sanitize
18136 ? this.options.sanitizer
18137 ? this.options.sanitizer(cap[0])
18144 if (cap = this.rules.link.exec(src)) {
18145 src = src.substring(cap[0].length);
18146 this.inLink = true;
18147 out += this.outputLink(cap, {
18151 this.inLink = false;
18156 if ((cap = this.rules.reflink.exec(src))
18157 || (cap = this.rules.nolink.exec(src))) {
18158 src = src.substring(cap[0].length);
18159 link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
18160 link = this.links[link.toLowerCase()];
18161 if (!link || !link.href) {
18162 out += cap[0].charAt(0);
18163 src = cap[0].substring(1) + src;
18166 this.inLink = true;
18167 out += this.outputLink(cap, link);
18168 this.inLink = false;
18173 if (cap = this.rules.strong.exec(src)) {
18174 src = src.substring(cap[0].length);
18175 out += this.renderer.strong(this.output(cap[2] || cap[1]));
18180 if (cap = this.rules.em.exec(src)) {
18181 src = src.substring(cap[0].length);
18182 out += this.renderer.em(this.output(cap[2] || cap[1]));
18187 if (cap = this.rules.code.exec(src)) {
18188 src = src.substring(cap[0].length);
18189 out += this.renderer.codespan(escape(cap[2], true));
18194 if (cap = this.rules.br.exec(src)) {
18195 src = src.substring(cap[0].length);
18196 out += this.renderer.br();
18201 if (cap = this.rules.del.exec(src)) {
18202 src = src.substring(cap[0].length);
18203 out += this.renderer.del(this.output(cap[1]));
18208 if (cap = this.rules.text.exec(src)) {
18209 src = src.substring(cap[0].length);
18210 out += this.renderer.text(escape(this.smartypants(cap[0])));
18216 Error('Infinite loop on byte: ' + src.charCodeAt(0));
18227 InlineLexer.prototype.outputLink = function(cap, link) {
18228 var href = escape(link.href)
18229 , title = link.title ? escape(link.title) : null;
18231 return cap[0].charAt(0) !== '!'
18232 ? this.renderer.link(href, title, this.output(cap[1]))
18233 : this.renderer.image(href, title, escape(cap[1]));
18237 * Smartypants Transformations
18240 InlineLexer.prototype.smartypants = function(text) {
18241 if (!this.options.smartypants) { return text; }
18244 .replace(/---/g, '\u2014')
18246 .replace(/--/g, '\u2013')
18248 .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
18249 // closing singles & apostrophes
18250 .replace(/'/g, '\u2019')
18252 .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
18254 .replace(/"/g, '\u201d')
18256 .replace(/\.{3}/g, '\u2026');
18263 InlineLexer.prototype.mangle = function(text) {
18264 if (!this.options.mangle) { return text; }
18270 for (; i < l; i++) {
18271 ch = text.charCodeAt(i);
18272 if (Math.random() > 0.5) {
18273 ch = 'x' + ch.toString(16);
18275 out += '&#' + ch + ';';
18286 * eval:var:Renderer
18289 var Renderer = function (options) {
18290 this.options = options || {};
18293 Renderer.prototype.code = function(code, lang, escaped) {
18294 if (this.options.highlight) {
18295 var out = this.options.highlight(code, lang);
18296 if (out != null && out !== code) {
18301 // hack!!! - it's already escapeD?
18306 return '<pre><code>'
18307 + (escaped ? code : escape(code, true))
18308 + '\n</code></pre>';
18311 return '<pre><code class="'
18312 + this.options.langPrefix
18313 + escape(lang, true)
18315 + (escaped ? code : escape(code, true))
18316 + '\n</code></pre>\n';
18319 Renderer.prototype.blockquote = function(quote) {
18320 return '<blockquote>\n' + quote + '</blockquote>\n';
18323 Renderer.prototype.html = function(html) {
18327 Renderer.prototype.heading = function(text, level, raw) {
18331 + this.options.headerPrefix
18332 + raw.toLowerCase().replace(/[^\w]+/g, '-')
18340 Renderer.prototype.hr = function() {
18341 return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
18344 Renderer.prototype.list = function(body, ordered) {
18345 var type = ordered ? 'ol' : 'ul';
18346 return '<' + type + '>\n' + body + '</' + type + '>\n';
18349 Renderer.prototype.listitem = function(text) {
18350 return '<li>' + text + '</li>\n';
18353 Renderer.prototype.paragraph = function(text) {
18354 return '<p>' + text + '</p>\n';
18357 Renderer.prototype.table = function(header, body) {
18358 return '<table class="table table-striped">\n'
18368 Renderer.prototype.tablerow = function(content) {
18369 return '<tr>\n' + content + '</tr>\n';
18372 Renderer.prototype.tablecell = function(content, flags) {
18373 var type = flags.header ? 'th' : 'td';
18374 var tag = flags.align
18375 ? '<' + type + ' style="text-align:' + flags.align + '">'
18376 : '<' + type + '>';
18377 return tag + content + '</' + type + '>\n';
18380 // span level renderer
18381 Renderer.prototype.strong = function(text) {
18382 return '<strong>' + text + '</strong>';
18385 Renderer.prototype.em = function(text) {
18386 return '<em>' + text + '</em>';
18389 Renderer.prototype.codespan = function(text) {
18390 return '<code>' + text + '</code>';
18393 Renderer.prototype.br = function() {
18394 return this.options.xhtml ? '<br/>' : '<br>';
18397 Renderer.prototype.del = function(text) {
18398 return '<del>' + text + '</del>';
18401 Renderer.prototype.link = function(href, title, text) {
18402 if (this.options.sanitize) {
18404 var prot = decodeURIComponent(unescape(href))
18405 .replace(/[^\w:]/g, '')
18410 if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) {
18414 var out = '<a href="' + href + '"';
18416 out += ' title="' + title + '"';
18418 out += '>' + text + '</a>';
18422 Renderer.prototype.image = function(href, title, text) {
18423 var out = '<img src="' + href + '" alt="' + text + '"';
18425 out += ' title="' + title + '"';
18427 out += this.options.xhtml ? '/>' : '>';
18431 Renderer.prototype.text = function(text) {
18436 * Parsing & Compiling
18442 var Parser= function (options) {
18445 this.options = options || marked.defaults;
18446 this.options.renderer = this.options.renderer || new Renderer;
18447 this.renderer = this.options.renderer;
18448 this.renderer.options = this.options;
18452 * Static Parse Method
18455 Parser.parse = function(src, options, renderer) {
18456 var parser = new Parser(options, renderer);
18457 return parser.parse(src);
18464 Parser.prototype.parse = function(src) {
18465 this.inline = new InlineLexer(src.links, this.options, this.renderer);
18466 this.tokens = src.reverse();
18469 while (this.next()) {
18480 Parser.prototype.next = function() {
18481 return this.token = this.tokens.pop();
18485 * Preview Next Token
18488 Parser.prototype.peek = function() {
18489 return this.tokens[this.tokens.length - 1] || 0;
18493 * Parse Text Tokens
18496 Parser.prototype.parseText = function() {
18497 var body = this.token.text;
18499 while (this.peek().type === 'text') {
18500 body += '\n' + this.next().text;
18503 return this.inline.output(body);
18507 * Parse Current Token
18510 Parser.prototype.tok = function() {
18511 switch (this.token.type) {
18516 return this.renderer.hr();
18519 return this.renderer.heading(
18520 this.inline.output(this.token.text),
18525 return this.renderer.code(this.token.text,
18527 this.token.escaped);
18540 for (i = 0; i < this.token.header.length; i++) {
18541 flags = { header: true, align: this.token.align[i] };
18542 cell += this.renderer.tablecell(
18543 this.inline.output(this.token.header[i]),
18544 { header: true, align: this.token.align[i] }
18547 header += this.renderer.tablerow(cell);
18549 for (i = 0; i < this.token.cells.length; i++) {
18550 row = this.token.cells[i];
18553 for (j = 0; j < row.length; j++) {
18554 cell += this.renderer.tablecell(
18555 this.inline.output(row[j]),
18556 { header: false, align: this.token.align[j] }
18560 body += this.renderer.tablerow(cell);
18562 return this.renderer.table(header, body);
18564 case 'blockquote_start': {
18567 while (this.next().type !== 'blockquote_end') {
18568 body += this.tok();
18571 return this.renderer.blockquote(body);
18573 case 'list_start': {
18575 , ordered = this.token.ordered;
18577 while (this.next().type !== 'list_end') {
18578 body += this.tok();
18581 return this.renderer.list(body, ordered);
18583 case 'list_item_start': {
18586 while (this.next().type !== 'list_item_end') {
18587 body += this.token.type === 'text'
18592 return this.renderer.listitem(body);
18594 case 'loose_item_start': {
18597 while (this.next().type !== 'list_item_end') {
18598 body += this.tok();
18601 return this.renderer.listitem(body);
18604 var html = !this.token.pre && !this.options.pedantic
18605 ? this.inline.output(this.token.text)
18607 return this.renderer.html(html);
18609 case 'paragraph': {
18610 return this.renderer.paragraph(this.inline.output(this.token.text));
18613 return this.renderer.paragraph(this.parseText());
18625 var marked = function (src, opt, callback) {
18626 if (callback || typeof opt === 'function') {
18632 opt = merge({}, marked.defaults, opt || {});
18634 var highlight = opt.highlight
18640 tokens = Lexer.lex(src, opt)
18642 return callback(e);
18645 pending = tokens.length;
18649 var done = function(err) {
18651 opt.highlight = highlight;
18652 return callback(err);
18658 out = Parser.parse(tokens, opt);
18663 opt.highlight = highlight;
18667 : callback(null, out);
18670 if (!highlight || highlight.length < 3) {
18674 delete opt.highlight;
18676 if (!pending) { return done(); }
18678 for (; i < tokens.length; i++) {
18680 if (token.type !== 'code') {
18681 return --pending || done();
18683 return highlight(token.text, token.lang, function(err, code) {
18684 if (err) { return done(err); }
18685 if (code == null || code === token.text) {
18686 return --pending || done();
18689 token.escaped = true;
18690 --pending || done();
18698 if (opt) { opt = merge({}, marked.defaults, opt); }
18699 return Parser.parse(Lexer.lex(src, opt), opt);
18701 e.message += '\nPlease report this to https://github.com/chjj/marked.';
18702 if ((opt || marked.defaults).silent) {
18703 return '<p>An error occured:</p><pre>'
18704 + escape(e.message + '', true)
18716 marked.setOptions = function(opt) {
18717 merge(marked.defaults, opt);
18721 marked.defaults = {
18732 langPrefix: 'lang-',
18733 smartypants: false,
18735 renderer: new Renderer,
18743 marked.Parser = Parser;
18744 marked.parser = Parser.parse;
18746 marked.Renderer = Renderer;
18748 marked.Lexer = Lexer;
18749 marked.lexer = Lexer.lex;
18751 marked.InlineLexer = InlineLexer;
18752 marked.inlineLexer = InlineLexer.output;
18754 marked.parse = marked;
18756 Roo.Markdown.marked = marked;
18760 * Ext JS Library 1.1.1
18761 * Copyright(c) 2006-2007, Ext JS, LLC.
18763 * Originally Released Under LGPL - original licence link has changed is not relivant.
18766 * <script type="text/javascript">
18772 * These classes are derivatives of the similarly named classes in the YUI Library.
18773 * The original license:
18774 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
18775 * Code licensed under the BSD License:
18776 * http://developer.yahoo.net/yui/license.txt
18781 var Event=Roo.EventManager;
18782 var Dom=Roo.lib.Dom;
18785 * @class Roo.dd.DragDrop
18786 * @extends Roo.util.Observable
18787 * Defines the interface and base operation of items that that can be
18788 * dragged or can be drop targets. It was designed to be extended, overriding
18789 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
18790 * Up to three html elements can be associated with a DragDrop instance:
18792 * <li>linked element: the element that is passed into the constructor.
18793 * This is the element which defines the boundaries for interaction with
18794 * other DragDrop objects.</li>
18795 * <li>handle element(s): The drag operation only occurs if the element that
18796 * was clicked matches a handle element. By default this is the linked
18797 * element, but there are times that you will want only a portion of the
18798 * linked element to initiate the drag operation, and the setHandleElId()
18799 * method provides a way to define this.</li>
18800 * <li>drag element: this represents the element that would be moved along
18801 * with the cursor during a drag operation. By default, this is the linked
18802 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
18803 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
18806 * This class should not be instantiated until the onload event to ensure that
18807 * the associated elements are available.
18808 * The following would define a DragDrop obj that would interact with any
18809 * other DragDrop obj in the "group1" group:
18811 * dd = new Roo.dd.DragDrop("div1", "group1");
18813 * Since none of the event handlers have been implemented, nothing would
18814 * actually happen if you were to run the code above. Normally you would
18815 * override this class or one of the default implementations, but you can
18816 * also override the methods you want on an instance of the class...
18818 * dd.onDragDrop = function(e, id) {
18819 * alert("dd was dropped on " + id);
18823 * @param {String} id of the element that is linked to this instance
18824 * @param {String} sGroup the group of related DragDrop objects
18825 * @param {object} config an object containing configurable attributes
18826 * Valid properties for DragDrop:
18827 * padding, isTarget, maintainOffset, primaryButtonOnly
18829 Roo.dd.DragDrop = function(id, sGroup, config) {
18831 this.init(id, sGroup, config);
18836 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
18839 * The id of the element associated with this object. This is what we
18840 * refer to as the "linked element" because the size and position of
18841 * this element is used to determine when the drag and drop objects have
18849 * Configuration attributes passed into the constructor
18856 * The id of the element that will be dragged. By default this is same
18857 * as the linked element , but could be changed to another element. Ex:
18859 * @property dragElId
18866 * the id of the element that initiates the drag operation. By default
18867 * this is the linked element, but could be changed to be a child of this
18868 * element. This lets us do things like only starting the drag when the
18869 * header element within the linked html element is clicked.
18870 * @property handleElId
18877 * An associative array of HTML tags that will be ignored if clicked.
18878 * @property invalidHandleTypes
18879 * @type {string: string}
18881 invalidHandleTypes: null,
18884 * An associative array of ids for elements that will be ignored if clicked
18885 * @property invalidHandleIds
18886 * @type {string: string}
18888 invalidHandleIds: null,
18891 * An indexted array of css class names for elements that will be ignored
18893 * @property invalidHandleClasses
18896 invalidHandleClasses: null,
18899 * The linked element's absolute X position at the time the drag was
18901 * @property startPageX
18908 * The linked element's absolute X position at the time the drag was
18910 * @property startPageY
18917 * The group defines a logical collection of DragDrop objects that are
18918 * related. Instances only get events when interacting with other
18919 * DragDrop object in the same group. This lets us define multiple
18920 * groups using a single DragDrop subclass if we want.
18922 * @type {string: string}
18927 * Individual drag/drop instances can be locked. This will prevent
18928 * onmousedown start drag.
18936 * Lock this instance
18939 lock: function() { this.locked = true; },
18942 * Unlock this instace
18945 unlock: function() { this.locked = false; },
18948 * By default, all insances can be a drop target. This can be disabled by
18949 * setting isTarget to false.
18956 * The padding configured for this drag and drop object for calculating
18957 * the drop zone intersection with this object.
18964 * Cached reference to the linked element
18965 * @property _domRef
18971 * Internal typeof flag
18972 * @property __ygDragDrop
18975 __ygDragDrop: true,
18978 * Set to true when horizontal contraints are applied
18979 * @property constrainX
18986 * Set to true when vertical contraints are applied
18987 * @property constrainY
18994 * The left constraint
19002 * The right constraint
19010 * The up constraint
19019 * The down constraint
19027 * Maintain offsets when we resetconstraints. Set to true when you want
19028 * the position of the element relative to its parent to stay the same
19029 * when the page changes
19031 * @property maintainOffset
19034 maintainOffset: false,
19037 * Array of pixel locations the element will snap to if we specified a
19038 * horizontal graduation/interval. This array is generated automatically
19039 * when you define a tick interval.
19046 * Array of pixel locations the element will snap to if we specified a
19047 * vertical graduation/interval. This array is generated automatically
19048 * when you define a tick interval.
19055 * By default the drag and drop instance will only respond to the primary
19056 * button click (left button for a right-handed mouse). Set to true to
19057 * allow drag and drop to start with any mouse click that is propogated
19059 * @property primaryButtonOnly
19062 primaryButtonOnly: true,
19065 * The availabe property is false until the linked dom element is accessible.
19066 * @property available
19072 * By default, drags can only be initiated if the mousedown occurs in the
19073 * region the linked element is. This is done in part to work around a
19074 * bug in some browsers that mis-report the mousedown if the previous
19075 * mouseup happened outside of the window. This property is set to true
19076 * if outer handles are defined.
19078 * @property hasOuterHandles
19082 hasOuterHandles: false,
19085 * Code that executes immediately before the startDrag event
19086 * @method b4StartDrag
19089 b4StartDrag: function(x, y) { },
19092 * Abstract method called after a drag/drop object is clicked
19093 * and the drag or mousedown time thresholds have beeen met.
19094 * @method startDrag
19095 * @param {int} X click location
19096 * @param {int} Y click location
19098 startDrag: function(x, y) { /* override this */ },
19101 * Code that executes immediately before the onDrag event
19105 b4Drag: function(e) { },
19108 * Abstract method called during the onMouseMove event while dragging an
19111 * @param {Event} e the mousemove event
19113 onDrag: function(e) { /* override this */ },
19116 * Abstract method called when this element fist begins hovering over
19117 * another DragDrop obj
19118 * @method onDragEnter
19119 * @param {Event} e the mousemove event
19120 * @param {String|DragDrop[]} id In POINT mode, the element
19121 * id this is hovering over. In INTERSECT mode, an array of one or more
19122 * dragdrop items being hovered over.
19124 onDragEnter: function(e, id) { /* override this */ },
19127 * Code that executes immediately before the onDragOver event
19128 * @method b4DragOver
19131 b4DragOver: function(e) { },
19134 * Abstract method called when this element is hovering over another
19136 * @method onDragOver
19137 * @param {Event} e the mousemove event
19138 * @param {String|DragDrop[]} id In POINT mode, the element
19139 * id this is hovering over. In INTERSECT mode, an array of dd items
19140 * being hovered over.
19142 onDragOver: function(e, id) { /* override this */ },
19145 * Code that executes immediately before the onDragOut event
19146 * @method b4DragOut
19149 b4DragOut: function(e) { },
19152 * Abstract method called when we are no longer hovering over an element
19153 * @method onDragOut
19154 * @param {Event} e the mousemove event
19155 * @param {String|DragDrop[]} id In POINT mode, the element
19156 * id this was hovering over. In INTERSECT mode, an array of dd items
19157 * that the mouse is no longer over.
19159 onDragOut: function(e, id) { /* override this */ },
19162 * Code that executes immediately before the onDragDrop event
19163 * @method b4DragDrop
19166 b4DragDrop: function(e) { },
19169 * Abstract method called when this item is dropped on another DragDrop
19171 * @method onDragDrop
19172 * @param {Event} e the mouseup event
19173 * @param {String|DragDrop[]} id In POINT mode, the element
19174 * id this was dropped on. In INTERSECT mode, an array of dd items this
19177 onDragDrop: function(e, id) { /* override this */ },
19180 * Abstract method called when this item is dropped on an area with no
19182 * @method onInvalidDrop
19183 * @param {Event} e the mouseup event
19185 onInvalidDrop: function(e) { /* override this */ },
19188 * Code that executes immediately before the endDrag event
19189 * @method b4EndDrag
19192 b4EndDrag: function(e) { },
19195 * Fired when we are done dragging the object
19197 * @param {Event} e the mouseup event
19199 endDrag: function(e) { /* override this */ },
19202 * Code executed immediately before the onMouseDown event
19203 * @method b4MouseDown
19204 * @param {Event} e the mousedown event
19207 b4MouseDown: function(e) { },
19210 * Event handler that fires when a drag/drop obj gets a mousedown
19211 * @method onMouseDown
19212 * @param {Event} e the mousedown event
19214 onMouseDown: function(e) { /* override this */ },
19217 * Event handler that fires when a drag/drop obj gets a mouseup
19218 * @method onMouseUp
19219 * @param {Event} e the mouseup event
19221 onMouseUp: function(e) { /* override this */ },
19224 * Override the onAvailable method to do what is needed after the initial
19225 * position was determined.
19226 * @method onAvailable
19228 onAvailable: function () {
19232 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
19235 defaultPadding : {left:0, right:0, top:0, bottom:0},
19238 * Initializes the drag drop object's constraints to restrict movement to a certain element.
19242 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
19243 { dragElId: "existingProxyDiv" });
19244 dd.startDrag = function(){
19245 this.constrainTo("parent-id");
19248 * Or you can initalize it using the {@link Roo.Element} object:
19250 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
19251 startDrag : function(){
19252 this.constrainTo("parent-id");
19256 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
19257 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
19258 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
19259 * an object containing the sides to pad. For example: {right:10, bottom:10}
19260 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
19262 constrainTo : function(constrainTo, pad, inContent){
19263 if(typeof pad == "number"){
19264 pad = {left: pad, right:pad, top:pad, bottom:pad};
19266 pad = pad || this.defaultPadding;
19267 var b = Roo.get(this.getEl()).getBox();
19268 var ce = Roo.get(constrainTo);
19269 var s = ce.getScroll();
19270 var c, cd = ce.dom;
19271 if(cd == document.body){
19272 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
19275 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
19279 var topSpace = b.y - c.y;
19280 var leftSpace = b.x - c.x;
19282 this.resetConstraints();
19283 this.setXConstraint(leftSpace - (pad.left||0), // left
19284 c.width - leftSpace - b.width - (pad.right||0) //right
19286 this.setYConstraint(topSpace - (pad.top||0), //top
19287 c.height - topSpace - b.height - (pad.bottom||0) //bottom
19292 * Returns a reference to the linked element
19294 * @return {HTMLElement} the html element
19296 getEl: function() {
19297 if (!this._domRef) {
19298 this._domRef = Roo.getDom(this.id);
19301 return this._domRef;
19305 * Returns a reference to the actual element to drag. By default this is
19306 * the same as the html element, but it can be assigned to another
19307 * element. An example of this can be found in Roo.dd.DDProxy
19308 * @method getDragEl
19309 * @return {HTMLElement} the html element
19311 getDragEl: function() {
19312 return Roo.getDom(this.dragElId);
19316 * Sets up the DragDrop object. Must be called in the constructor of any
19317 * Roo.dd.DragDrop subclass
19319 * @param id the id of the linked element
19320 * @param {String} sGroup the group of related items
19321 * @param {object} config configuration attributes
19323 init: function(id, sGroup, config) {
19324 this.initTarget(id, sGroup, config);
19325 if (!Roo.isTouch) {
19326 Event.on(this.id, "mousedown", this.handleMouseDown, this);
19328 Event.on(this.id, "touchstart", this.handleMouseDown, this);
19329 // Event.on(this.id, "selectstart", Event.preventDefault);
19333 * Initializes Targeting functionality only... the object does not
19334 * get a mousedown handler.
19335 * @method initTarget
19336 * @param id the id of the linked element
19337 * @param {String} sGroup the group of related items
19338 * @param {object} config configuration attributes
19340 initTarget: function(id, sGroup, config) {
19342 // configuration attributes
19343 this.config = config || {};
19345 // create a local reference to the drag and drop manager
19346 this.DDM = Roo.dd.DDM;
19347 // initialize the groups array
19350 // assume that we have an element reference instead of an id if the
19351 // parameter is not a string
19352 if (typeof id !== "string") {
19359 // add to an interaction group
19360 this.addToGroup((sGroup) ? sGroup : "default");
19362 // We don't want to register this as the handle with the manager
19363 // so we just set the id rather than calling the setter.
19364 this.handleElId = id;
19366 // the linked element is the element that gets dragged by default
19367 this.setDragElId(id);
19369 // by default, clicked anchors will not start drag operations.
19370 this.invalidHandleTypes = { A: "A" };
19371 this.invalidHandleIds = {};
19372 this.invalidHandleClasses = [];
19374 this.applyConfig();
19376 this.handleOnAvailable();
19380 * Applies the configuration parameters that were passed into the constructor.
19381 * This is supposed to happen at each level through the inheritance chain. So
19382 * a DDProxy implentation will execute apply config on DDProxy, DD, and
19383 * DragDrop in order to get all of the parameters that are available in
19385 * @method applyConfig
19387 applyConfig: function() {
19389 // configurable properties:
19390 // padding, isTarget, maintainOffset, primaryButtonOnly
19391 this.padding = this.config.padding || [0, 0, 0, 0];
19392 this.isTarget = (this.config.isTarget !== false);
19393 this.maintainOffset = (this.config.maintainOffset);
19394 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
19399 * Executed when the linked element is available
19400 * @method handleOnAvailable
19403 handleOnAvailable: function() {
19404 this.available = true;
19405 this.resetConstraints();
19406 this.onAvailable();
19410 * Configures the padding for the target zone in px. Effectively expands
19411 * (or reduces) the virtual object size for targeting calculations.
19412 * Supports css-style shorthand; if only one parameter is passed, all sides
19413 * will have that padding, and if only two are passed, the top and bottom
19414 * will have the first param, the left and right the second.
19415 * @method setPadding
19416 * @param {int} iTop Top pad
19417 * @param {int} iRight Right pad
19418 * @param {int} iBot Bot pad
19419 * @param {int} iLeft Left pad
19421 setPadding: function(iTop, iRight, iBot, iLeft) {
19422 // this.padding = [iLeft, iRight, iTop, iBot];
19423 if (!iRight && 0 !== iRight) {
19424 this.padding = [iTop, iTop, iTop, iTop];
19425 } else if (!iBot && 0 !== iBot) {
19426 this.padding = [iTop, iRight, iTop, iRight];
19428 this.padding = [iTop, iRight, iBot, iLeft];
19433 * Stores the initial placement of the linked element.
19434 * @method setInitialPosition
19435 * @param {int} diffX the X offset, default 0
19436 * @param {int} diffY the Y offset, default 0
19438 setInitPosition: function(diffX, diffY) {
19439 var el = this.getEl();
19441 if (!this.DDM.verifyEl(el)) {
19445 var dx = diffX || 0;
19446 var dy = diffY || 0;
19448 var p = Dom.getXY( el );
19450 this.initPageX = p[0] - dx;
19451 this.initPageY = p[1] - dy;
19453 this.lastPageX = p[0];
19454 this.lastPageY = p[1];
19457 this.setStartPosition(p);
19461 * Sets the start position of the element. This is set when the obj
19462 * is initialized, the reset when a drag is started.
19463 * @method setStartPosition
19464 * @param pos current position (from previous lookup)
19467 setStartPosition: function(pos) {
19468 var p = pos || Dom.getXY( this.getEl() );
19469 this.deltaSetXY = null;
19471 this.startPageX = p[0];
19472 this.startPageY = p[1];
19476 * Add this instance to a group of related drag/drop objects. All
19477 * instances belong to at least one group, and can belong to as many
19478 * groups as needed.
19479 * @method addToGroup
19480 * @param sGroup {string} the name of the group
19482 addToGroup: function(sGroup) {
19483 this.groups[sGroup] = true;
19484 this.DDM.regDragDrop(this, sGroup);
19488 * Remove's this instance from the supplied interaction group
19489 * @method removeFromGroup
19490 * @param {string} sGroup The group to drop
19492 removeFromGroup: function(sGroup) {
19493 if (this.groups[sGroup]) {
19494 delete this.groups[sGroup];
19497 this.DDM.removeDDFromGroup(this, sGroup);
19501 * Allows you to specify that an element other than the linked element
19502 * will be moved with the cursor during a drag
19503 * @method setDragElId
19504 * @param id {string} the id of the element that will be used to initiate the drag
19506 setDragElId: function(id) {
19507 this.dragElId = id;
19511 * Allows you to specify a child of the linked element that should be
19512 * used to initiate the drag operation. An example of this would be if
19513 * you have a content div with text and links. Clicking anywhere in the
19514 * content area would normally start the drag operation. Use this method
19515 * to specify that an element inside of the content div is the element
19516 * that starts the drag operation.
19517 * @method setHandleElId
19518 * @param id {string} the id of the element that will be used to
19519 * initiate the drag.
19521 setHandleElId: function(id) {
19522 if (typeof id !== "string") {
19525 this.handleElId = id;
19526 this.DDM.regHandle(this.id, id);
19530 * Allows you to set an element outside of the linked element as a drag
19532 * @method setOuterHandleElId
19533 * @param id the id of the element that will be used to initiate the drag
19535 setOuterHandleElId: function(id) {
19536 if (typeof id !== "string") {
19539 Event.on(id, "mousedown",
19540 this.handleMouseDown, this);
19541 this.setHandleElId(id);
19543 this.hasOuterHandles = true;
19547 * Remove all drag and drop hooks for this element
19550 unreg: function() {
19551 Event.un(this.id, "mousedown",
19552 this.handleMouseDown);
19553 Event.un(this.id, "touchstart",
19554 this.handleMouseDown);
19555 this._domRef = null;
19556 this.DDM._remove(this);
19559 destroy : function(){
19564 * Returns true if this instance is locked, or the drag drop mgr is locked
19565 * (meaning that all drag/drop is disabled on the page.)
19567 * @return {boolean} true if this obj or all drag/drop is locked, else
19570 isLocked: function() {
19571 return (this.DDM.isLocked() || this.locked);
19575 * Fired when this object is clicked
19576 * @method handleMouseDown
19578 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
19581 handleMouseDown: function(e, oDD){
19583 if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
19584 //Roo.log('not touch/ button !=0');
19587 if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
19588 return; // double touch..
19592 if (this.isLocked()) {
19593 //Roo.log('locked');
19597 this.DDM.refreshCache(this.groups);
19598 // Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
19599 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
19600 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
19601 //Roo.log('no outer handes or not over target');
19604 // Roo.log('check validator');
19605 if (this.clickValidator(e)) {
19606 // Roo.log('validate success');
19607 // set the initial element position
19608 this.setStartPosition();
19611 this.b4MouseDown(e);
19612 this.onMouseDown(e);
19614 this.DDM.handleMouseDown(e, this);
19616 this.DDM.stopEvent(e);
19624 clickValidator: function(e) {
19625 var target = e.getTarget();
19626 return ( this.isValidHandleChild(target) &&
19627 (this.id == this.handleElId ||
19628 this.DDM.handleWasClicked(target, this.id)) );
19632 * Allows you to specify a tag name that should not start a drag operation
19633 * when clicked. This is designed to facilitate embedding links within a
19634 * drag handle that do something other than start the drag.
19635 * @method addInvalidHandleType
19636 * @param {string} tagName the type of element to exclude
19638 addInvalidHandleType: function(tagName) {
19639 var type = tagName.toUpperCase();
19640 this.invalidHandleTypes[type] = type;
19644 * Lets you to specify an element id for a child of a drag handle
19645 * that should not initiate a drag
19646 * @method addInvalidHandleId
19647 * @param {string} id the element id of the element you wish to ignore
19649 addInvalidHandleId: function(id) {
19650 if (typeof id !== "string") {
19653 this.invalidHandleIds[id] = id;
19657 * Lets you specify a css class of elements that will not initiate a drag
19658 * @method addInvalidHandleClass
19659 * @param {string} cssClass the class of the elements you wish to ignore
19661 addInvalidHandleClass: function(cssClass) {
19662 this.invalidHandleClasses.push(cssClass);
19666 * Unsets an excluded tag name set by addInvalidHandleType
19667 * @method removeInvalidHandleType
19668 * @param {string} tagName the type of element to unexclude
19670 removeInvalidHandleType: function(tagName) {
19671 var type = tagName.toUpperCase();
19672 // this.invalidHandleTypes[type] = null;
19673 delete this.invalidHandleTypes[type];
19677 * Unsets an invalid handle id
19678 * @method removeInvalidHandleId
19679 * @param {string} id the id of the element to re-enable
19681 removeInvalidHandleId: function(id) {
19682 if (typeof id !== "string") {
19685 delete this.invalidHandleIds[id];
19689 * Unsets an invalid css class
19690 * @method removeInvalidHandleClass
19691 * @param {string} cssClass the class of the element(s) you wish to
19694 removeInvalidHandleClass: function(cssClass) {
19695 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
19696 if (this.invalidHandleClasses[i] == cssClass) {
19697 delete this.invalidHandleClasses[i];
19703 * Checks the tag exclusion list to see if this click should be ignored
19704 * @method isValidHandleChild
19705 * @param {HTMLElement} node the HTMLElement to evaluate
19706 * @return {boolean} true if this is a valid tag type, false if not
19708 isValidHandleChild: function(node) {
19711 // var n = (node.nodeName == "#text") ? node.parentNode : node;
19714 nodeName = node.nodeName.toUpperCase();
19716 nodeName = node.nodeName;
19718 valid = valid && !this.invalidHandleTypes[nodeName];
19719 valid = valid && !this.invalidHandleIds[node.id];
19721 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
19722 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
19731 * Create the array of horizontal tick marks if an interval was specified
19732 * in setXConstraint().
19733 * @method setXTicks
19736 setXTicks: function(iStartX, iTickSize) {
19738 this.xTickSize = iTickSize;
19742 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
19744 this.xTicks[this.xTicks.length] = i;
19749 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
19751 this.xTicks[this.xTicks.length] = i;
19756 this.xTicks.sort(this.DDM.numericSort) ;
19760 * Create the array of vertical tick marks if an interval was specified in
19761 * setYConstraint().
19762 * @method setYTicks
19765 setYTicks: function(iStartY, iTickSize) {
19767 this.yTickSize = iTickSize;
19771 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
19773 this.yTicks[this.yTicks.length] = i;
19778 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
19780 this.yTicks[this.yTicks.length] = i;
19785 this.yTicks.sort(this.DDM.numericSort) ;
19789 * By default, the element can be dragged any place on the screen. Use
19790 * this method to limit the horizontal travel of the element. Pass in
19791 * 0,0 for the parameters if you want to lock the drag to the y axis.
19792 * @method setXConstraint
19793 * @param {int} iLeft the number of pixels the element can move to the left
19794 * @param {int} iRight the number of pixels the element can move to the
19796 * @param {int} iTickSize optional parameter for specifying that the
19798 * should move iTickSize pixels at a time.
19800 setXConstraint: function(iLeft, iRight, iTickSize) {
19801 this.leftConstraint = iLeft;
19802 this.rightConstraint = iRight;
19804 this.minX = this.initPageX - iLeft;
19805 this.maxX = this.initPageX + iRight;
19806 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
19808 this.constrainX = true;
19812 * Clears any constraints applied to this instance. Also clears ticks
19813 * since they can't exist independent of a constraint at this time.
19814 * @method clearConstraints
19816 clearConstraints: function() {
19817 this.constrainX = false;
19818 this.constrainY = false;
19823 * Clears any tick interval defined for this instance
19824 * @method clearTicks
19826 clearTicks: function() {
19827 this.xTicks = null;
19828 this.yTicks = null;
19829 this.xTickSize = 0;
19830 this.yTickSize = 0;
19834 * By default, the element can be dragged any place on the screen. Set
19835 * this to limit the vertical travel of the element. Pass in 0,0 for the
19836 * parameters if you want to lock the drag to the x axis.
19837 * @method setYConstraint
19838 * @param {int} iUp the number of pixels the element can move up
19839 * @param {int} iDown the number of pixels the element can move down
19840 * @param {int} iTickSize optional parameter for specifying that the
19841 * element should move iTickSize pixels at a time.
19843 setYConstraint: function(iUp, iDown, iTickSize) {
19844 this.topConstraint = iUp;
19845 this.bottomConstraint = iDown;
19847 this.minY = this.initPageY - iUp;
19848 this.maxY = this.initPageY + iDown;
19849 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
19851 this.constrainY = true;
19856 * resetConstraints must be called if you manually reposition a dd element.
19857 * @method resetConstraints
19858 * @param {boolean} maintainOffset
19860 resetConstraints: function() {
19863 // Maintain offsets if necessary
19864 if (this.initPageX || this.initPageX === 0) {
19865 // figure out how much this thing has moved
19866 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
19867 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
19869 this.setInitPosition(dx, dy);
19871 // This is the first time we have detected the element's position
19873 this.setInitPosition();
19876 if (this.constrainX) {
19877 this.setXConstraint( this.leftConstraint,
19878 this.rightConstraint,
19882 if (this.constrainY) {
19883 this.setYConstraint( this.topConstraint,
19884 this.bottomConstraint,
19890 * Normally the drag element is moved pixel by pixel, but we can specify
19891 * that it move a number of pixels at a time. This method resolves the
19892 * location when we have it set up like this.
19894 * @param {int} val where we want to place the object
19895 * @param {int[]} tickArray sorted array of valid points
19896 * @return {int} the closest tick
19899 getTick: function(val, tickArray) {
19902 // If tick interval is not defined, it is effectively 1 pixel,
19903 // so we return the value passed to us.
19905 } else if (tickArray[0] >= val) {
19906 // The value is lower than the first tick, so we return the first
19908 return tickArray[0];
19910 for (var i=0, len=tickArray.length; i<len; ++i) {
19912 if (tickArray[next] && tickArray[next] >= val) {
19913 var diff1 = val - tickArray[i];
19914 var diff2 = tickArray[next] - val;
19915 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
19919 // The value is larger than the last tick, so we return the last
19921 return tickArray[tickArray.length - 1];
19928 * @return {string} string representation of the dd obj
19930 toString: function() {
19931 return ("DragDrop " + this.id);
19939 * Ext JS Library 1.1.1
19940 * Copyright(c) 2006-2007, Ext JS, LLC.
19942 * Originally Released Under LGPL - original licence link has changed is not relivant.
19945 * <script type="text/javascript">
19950 * The drag and drop utility provides a framework for building drag and drop
19951 * applications. In addition to enabling drag and drop for specific elements,
19952 * the drag and drop elements are tracked by the manager class, and the
19953 * interactions between the various elements are tracked during the drag and
19954 * the implementing code is notified about these important moments.
19957 // Only load the library once. Rewriting the manager class would orphan
19958 // existing drag and drop instances.
19959 if (!Roo.dd.DragDropMgr) {
19962 * @class Roo.dd.DragDropMgr
19963 * DragDropMgr is a singleton that tracks the element interaction for
19964 * all DragDrop items in the window. Generally, you will not call
19965 * this class directly, but it does have helper methods that could
19966 * be useful in your DragDrop implementations.
19969 Roo.dd.DragDropMgr = function() {
19971 var Event = Roo.EventManager;
19976 * Two dimensional Array of registered DragDrop objects. The first
19977 * dimension is the DragDrop item group, the second the DragDrop
19980 * @type {string: string}
19987 * Array of element ids defined as drag handles. Used to determine
19988 * if the element that generated the mousedown event is actually the
19989 * handle and not the html element itself.
19990 * @property handleIds
19991 * @type {string: string}
19998 * the DragDrop object that is currently being dragged
19999 * @property dragCurrent
20007 * the DragDrop object(s) that are being hovered over
20008 * @property dragOvers
20016 * the X distance between the cursor and the object being dragged
20025 * the Y distance between the cursor and the object being dragged
20034 * Flag to determine if we should prevent the default behavior of the
20035 * events we define. By default this is true, but this can be set to
20036 * false if you need the default behavior (not recommended)
20037 * @property preventDefault
20041 preventDefault: true,
20044 * Flag to determine if we should stop the propagation of the events
20045 * we generate. This is true by default but you may want to set it to
20046 * false if the html element contains other features that require the
20048 * @property stopPropagation
20052 stopPropagation: true,
20055 * Internal flag that is set to true when drag and drop has been
20057 * @property initialized
20064 * All drag and drop can be disabled.
20072 * Called the first time an element is registered.
20078 this.initialized = true;
20082 * In point mode, drag and drop interaction is defined by the
20083 * location of the cursor during the drag/drop
20091 * In intersect mode, drag and drop interactio nis defined by the
20092 * overlap of two or more drag and drop objects.
20093 * @property INTERSECT
20100 * The current drag and drop mode. Default: POINT
20108 * Runs method on all drag and drop objects
20109 * @method _execOnAll
20113 _execOnAll: function(sMethod, args) {
20114 for (var i in this.ids) {
20115 for (var j in this.ids[i]) {
20116 var oDD = this.ids[i][j];
20117 if (! this.isTypeOfDD(oDD)) {
20120 oDD[sMethod].apply(oDD, args);
20126 * Drag and drop initialization. Sets up the global event handlers
20131 _onLoad: function() {
20135 if (!Roo.isTouch) {
20136 Event.on(document, "mouseup", this.handleMouseUp, this, true);
20137 Event.on(document, "mousemove", this.handleMouseMove, this, true);
20139 Event.on(document, "touchend", this.handleMouseUp, this, true);
20140 Event.on(document, "touchmove", this.handleMouseMove, this, true);
20142 Event.on(window, "unload", this._onUnload, this, true);
20143 Event.on(window, "resize", this._onResize, this, true);
20144 // Event.on(window, "mouseout", this._test);
20149 * Reset constraints on all drag and drop objs
20150 * @method _onResize
20154 _onResize: function(e) {
20155 this._execOnAll("resetConstraints", []);
20159 * Lock all drag and drop functionality
20163 lock: function() { this.locked = true; },
20166 * Unlock all drag and drop functionality
20170 unlock: function() { this.locked = false; },
20173 * Is drag and drop locked?
20175 * @return {boolean} True if drag and drop is locked, false otherwise.
20178 isLocked: function() { return this.locked; },
20181 * Location cache that is set for all drag drop objects when a drag is
20182 * initiated, cleared when the drag is finished.
20183 * @property locationCache
20190 * Set useCache to false if you want to force object the lookup of each
20191 * drag and drop linked element constantly during a drag.
20192 * @property useCache
20199 * The number of pixels that the mouse needs to move after the
20200 * mousedown before the drag is initiated. Default=3;
20201 * @property clickPixelThresh
20205 clickPixelThresh: 3,
20208 * The number of milliseconds after the mousedown event to initiate the
20209 * drag if we don't get a mouseup event. Default=1000
20210 * @property clickTimeThresh
20214 clickTimeThresh: 350,
20217 * Flag that indicates that either the drag pixel threshold or the
20218 * mousdown time threshold has been met
20219 * @property dragThreshMet
20224 dragThreshMet: false,
20227 * Timeout used for the click time threshold
20228 * @property clickTimeout
20233 clickTimeout: null,
20236 * The X position of the mousedown event stored for later use when a
20237 * drag threshold is met.
20246 * The Y position of the mousedown event stored for later use when a
20247 * drag threshold is met.
20256 * Each DragDrop instance must be registered with the DragDropMgr.
20257 * This is executed in DragDrop.init()
20258 * @method regDragDrop
20259 * @param {DragDrop} oDD the DragDrop object to register
20260 * @param {String} sGroup the name of the group this element belongs to
20263 regDragDrop: function(oDD, sGroup) {
20264 if (!this.initialized) { this.init(); }
20266 if (!this.ids[sGroup]) {
20267 this.ids[sGroup] = {};
20269 this.ids[sGroup][oDD.id] = oDD;
20273 * Removes the supplied dd instance from the supplied group. Executed
20274 * by DragDrop.removeFromGroup, so don't call this function directly.
20275 * @method removeDDFromGroup
20279 removeDDFromGroup: function(oDD, sGroup) {
20280 if (!this.ids[sGroup]) {
20281 this.ids[sGroup] = {};
20284 var obj = this.ids[sGroup];
20285 if (obj && obj[oDD.id]) {
20286 delete obj[oDD.id];
20291 * Unregisters a drag and drop item. This is executed in
20292 * DragDrop.unreg, use that method instead of calling this directly.
20297 _remove: function(oDD) {
20298 for (var g in oDD.groups) {
20299 if (g && this.ids[g][oDD.id]) {
20300 delete this.ids[g][oDD.id];
20303 delete this.handleIds[oDD.id];
20307 * Each DragDrop handle element must be registered. This is done
20308 * automatically when executing DragDrop.setHandleElId()
20309 * @method regHandle
20310 * @param {String} sDDId the DragDrop id this element is a handle for
20311 * @param {String} sHandleId the id of the element that is the drag
20315 regHandle: function(sDDId, sHandleId) {
20316 if (!this.handleIds[sDDId]) {
20317 this.handleIds[sDDId] = {};
20319 this.handleIds[sDDId][sHandleId] = sHandleId;
20323 * Utility function to determine if a given element has been
20324 * registered as a drag drop item.
20325 * @method isDragDrop
20326 * @param {String} id the element id to check
20327 * @return {boolean} true if this element is a DragDrop item,
20331 isDragDrop: function(id) {
20332 return ( this.getDDById(id) ) ? true : false;
20336 * Returns the drag and drop instances that are in all groups the
20337 * passed in instance belongs to.
20338 * @method getRelated
20339 * @param {DragDrop} p_oDD the obj to get related data for
20340 * @param {boolean} bTargetsOnly if true, only return targetable objs
20341 * @return {DragDrop[]} the related instances
20344 getRelated: function(p_oDD, bTargetsOnly) {
20346 for (var i in p_oDD.groups) {
20347 for (j in this.ids[i]) {
20348 var dd = this.ids[i][j];
20349 if (! this.isTypeOfDD(dd)) {
20352 if (!bTargetsOnly || dd.isTarget) {
20353 oDDs[oDDs.length] = dd;
20362 * Returns true if the specified dd target is a legal target for
20363 * the specifice drag obj
20364 * @method isLegalTarget
20365 * @param {DragDrop} the drag obj
20366 * @param {DragDrop} the target
20367 * @return {boolean} true if the target is a legal target for the
20371 isLegalTarget: function (oDD, oTargetDD) {
20372 var targets = this.getRelated(oDD, true);
20373 for (var i=0, len=targets.length;i<len;++i) {
20374 if (targets[i].id == oTargetDD.id) {
20383 * My goal is to be able to transparently determine if an object is
20384 * typeof DragDrop, and the exact subclass of DragDrop. typeof
20385 * returns "object", oDD.constructor.toString() always returns
20386 * "DragDrop" and not the name of the subclass. So for now it just
20387 * evaluates a well-known variable in DragDrop.
20388 * @method isTypeOfDD
20389 * @param {Object} the object to evaluate
20390 * @return {boolean} true if typeof oDD = DragDrop
20393 isTypeOfDD: function (oDD) {
20394 return (oDD && oDD.__ygDragDrop);
20398 * Utility function to determine if a given element has been
20399 * registered as a drag drop handle for the given Drag Drop object.
20401 * @param {String} id the element id to check
20402 * @return {boolean} true if this element is a DragDrop handle, false
20406 isHandle: function(sDDId, sHandleId) {
20407 return ( this.handleIds[sDDId] &&
20408 this.handleIds[sDDId][sHandleId] );
20412 * Returns the DragDrop instance for a given id
20413 * @method getDDById
20414 * @param {String} id the id of the DragDrop object
20415 * @return {DragDrop} the drag drop object, null if it is not found
20418 getDDById: function(id) {
20419 for (var i in this.ids) {
20420 if (this.ids[i][id]) {
20421 return this.ids[i][id];
20428 * Fired after a registered DragDrop object gets the mousedown event.
20429 * Sets up the events required to track the object being dragged
20430 * @method handleMouseDown
20431 * @param {Event} e the event
20432 * @param oDD the DragDrop object being dragged
20436 handleMouseDown: function(e, oDD) {
20438 Roo.QuickTips.disable();
20440 this.currentTarget = e.getTarget();
20442 this.dragCurrent = oDD;
20444 var el = oDD.getEl();
20446 // track start position
20447 this.startX = e.getPageX();
20448 this.startY = e.getPageY();
20450 this.deltaX = this.startX - el.offsetLeft;
20451 this.deltaY = this.startY - el.offsetTop;
20453 this.dragThreshMet = false;
20455 this.clickTimeout = setTimeout(
20457 var DDM = Roo.dd.DDM;
20458 DDM.startDrag(DDM.startX, DDM.startY);
20460 this.clickTimeThresh );
20464 * Fired when either the drag pixel threshol or the mousedown hold
20465 * time threshold has been met.
20466 * @method startDrag
20467 * @param x {int} the X position of the original mousedown
20468 * @param y {int} the Y position of the original mousedown
20471 startDrag: function(x, y) {
20472 clearTimeout(this.clickTimeout);
20473 if (this.dragCurrent) {
20474 this.dragCurrent.b4StartDrag(x, y);
20475 this.dragCurrent.startDrag(x, y);
20477 this.dragThreshMet = true;
20481 * Internal function to handle the mouseup event. Will be invoked
20482 * from the context of the document.
20483 * @method handleMouseUp
20484 * @param {Event} e the event
20488 handleMouseUp: function(e) {
20491 Roo.QuickTips.enable();
20493 if (! this.dragCurrent) {
20497 clearTimeout(this.clickTimeout);
20499 if (this.dragThreshMet) {
20500 this.fireEvents(e, true);
20510 * Utility to stop event propagation and event default, if these
20511 * features are turned on.
20512 * @method stopEvent
20513 * @param {Event} e the event as returned by this.getEvent()
20516 stopEvent: function(e){
20517 if(this.stopPropagation) {
20518 e.stopPropagation();
20521 if (this.preventDefault) {
20522 e.preventDefault();
20527 * Internal function to clean up event handlers after the drag
20528 * operation is complete
20530 * @param {Event} e the event
20534 stopDrag: function(e) {
20535 // Fire the drag end event for the item that was dragged
20536 if (this.dragCurrent) {
20537 if (this.dragThreshMet) {
20538 this.dragCurrent.b4EndDrag(e);
20539 this.dragCurrent.endDrag(e);
20542 this.dragCurrent.onMouseUp(e);
20545 this.dragCurrent = null;
20546 this.dragOvers = {};
20550 * Internal function to handle the mousemove event. Will be invoked
20551 * from the context of the html element.
20553 * @TODO figure out what we can do about mouse events lost when the
20554 * user drags objects beyond the window boundary. Currently we can
20555 * detect this in internet explorer by verifying that the mouse is
20556 * down during the mousemove event. Firefox doesn't give us the
20557 * button state on the mousemove event.
20558 * @method handleMouseMove
20559 * @param {Event} e the event
20563 handleMouseMove: function(e) {
20564 if (! this.dragCurrent) {
20568 // var button = e.which || e.button;
20570 // check for IE mouseup outside of page boundary
20571 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
20573 return this.handleMouseUp(e);
20576 if (!this.dragThreshMet) {
20577 var diffX = Math.abs(this.startX - e.getPageX());
20578 var diffY = Math.abs(this.startY - e.getPageY());
20579 if (diffX > this.clickPixelThresh ||
20580 diffY > this.clickPixelThresh) {
20581 this.startDrag(this.startX, this.startY);
20585 if (this.dragThreshMet) {
20586 this.dragCurrent.b4Drag(e);
20587 this.dragCurrent.onDrag(e);
20588 if(!this.dragCurrent.moveOnly){
20589 this.fireEvents(e, false);
20599 * Iterates over all of the DragDrop elements to find ones we are
20600 * hovering over or dropping on
20601 * @method fireEvents
20602 * @param {Event} e the event
20603 * @param {boolean} isDrop is this a drop op or a mouseover op?
20607 fireEvents: function(e, isDrop) {
20608 var dc = this.dragCurrent;
20610 // If the user did the mouse up outside of the window, we could
20611 // get here even though we have ended the drag.
20612 if (!dc || dc.isLocked()) {
20616 var pt = e.getPoint();
20618 // cache the previous dragOver array
20624 var enterEvts = [];
20626 // Check to see if the object(s) we were hovering over is no longer
20627 // being hovered over so we can fire the onDragOut event
20628 for (var i in this.dragOvers) {
20630 var ddo = this.dragOvers[i];
20632 if (! this.isTypeOfDD(ddo)) {
20636 if (! this.isOverTarget(pt, ddo, this.mode)) {
20637 outEvts.push( ddo );
20640 oldOvers[i] = true;
20641 delete this.dragOvers[i];
20644 for (var sGroup in dc.groups) {
20646 if ("string" != typeof sGroup) {
20650 for (i in this.ids[sGroup]) {
20651 var oDD = this.ids[sGroup][i];
20652 if (! this.isTypeOfDD(oDD)) {
20656 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
20657 if (this.isOverTarget(pt, oDD, this.mode)) {
20658 // look for drop interactions
20660 dropEvts.push( oDD );
20661 // look for drag enter and drag over interactions
20664 // initial drag over: dragEnter fires
20665 if (!oldOvers[oDD.id]) {
20666 enterEvts.push( oDD );
20667 // subsequent drag overs: dragOver fires
20669 overEvts.push( oDD );
20672 this.dragOvers[oDD.id] = oDD;
20680 if (outEvts.length) {
20681 dc.b4DragOut(e, outEvts);
20682 dc.onDragOut(e, outEvts);
20685 if (enterEvts.length) {
20686 dc.onDragEnter(e, enterEvts);
20689 if (overEvts.length) {
20690 dc.b4DragOver(e, overEvts);
20691 dc.onDragOver(e, overEvts);
20694 if (dropEvts.length) {
20695 dc.b4DragDrop(e, dropEvts);
20696 dc.onDragDrop(e, dropEvts);
20700 // fire dragout events
20702 for (i=0, len=outEvts.length; i<len; ++i) {
20703 dc.b4DragOut(e, outEvts[i].id);
20704 dc.onDragOut(e, outEvts[i].id);
20707 // fire enter events
20708 for (i=0,len=enterEvts.length; i<len; ++i) {
20709 // dc.b4DragEnter(e, oDD.id);
20710 dc.onDragEnter(e, enterEvts[i].id);
20713 // fire over events
20714 for (i=0,len=overEvts.length; i<len; ++i) {
20715 dc.b4DragOver(e, overEvts[i].id);
20716 dc.onDragOver(e, overEvts[i].id);
20719 // fire drop events
20720 for (i=0, len=dropEvts.length; i<len; ++i) {
20721 dc.b4DragDrop(e, dropEvts[i].id);
20722 dc.onDragDrop(e, dropEvts[i].id);
20727 // notify about a drop that did not find a target
20728 if (isDrop && !dropEvts.length) {
20729 dc.onInvalidDrop(e);
20735 * Helper function for getting the best match from the list of drag
20736 * and drop objects returned by the drag and drop events when we are
20737 * in INTERSECT mode. It returns either the first object that the
20738 * cursor is over, or the object that has the greatest overlap with
20739 * the dragged element.
20740 * @method getBestMatch
20741 * @param {DragDrop[]} dds The array of drag and drop objects
20743 * @return {DragDrop} The best single match
20746 getBestMatch: function(dds) {
20748 // Return null if the input is not what we expect
20749 //if (!dds || !dds.length || dds.length == 0) {
20751 // If there is only one item, it wins
20752 //} else if (dds.length == 1) {
20754 var len = dds.length;
20759 // Loop through the targeted items
20760 for (var i=0; i<len; ++i) {
20762 // If the cursor is over the object, it wins. If the
20763 // cursor is over multiple matches, the first one we come
20765 if (dd.cursorIsOver) {
20768 // Otherwise the object with the most overlap wins
20771 winner.overlap.getArea() < dd.overlap.getArea()) {
20782 * Refreshes the cache of the top-left and bottom-right points of the
20783 * drag and drop objects in the specified group(s). This is in the
20784 * format that is stored in the drag and drop instance, so typical
20787 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
20791 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
20793 * @TODO this really should be an indexed array. Alternatively this
20794 * method could accept both.
20795 * @method refreshCache
20796 * @param {Object} groups an associative array of groups to refresh
20799 refreshCache: function(groups) {
20800 for (var sGroup in groups) {
20801 if ("string" != typeof sGroup) {
20804 for (var i in this.ids[sGroup]) {
20805 var oDD = this.ids[sGroup][i];
20807 if (this.isTypeOfDD(oDD)) {
20808 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
20809 var loc = this.getLocation(oDD);
20811 this.locationCache[oDD.id] = loc;
20813 delete this.locationCache[oDD.id];
20814 // this will unregister the drag and drop object if
20815 // the element is not in a usable state
20824 * This checks to make sure an element exists and is in the DOM. The
20825 * main purpose is to handle cases where innerHTML is used to remove
20826 * drag and drop objects from the DOM. IE provides an 'unspecified
20827 * error' when trying to access the offsetParent of such an element
20829 * @param {HTMLElement} el the element to check
20830 * @return {boolean} true if the element looks usable
20833 verifyEl: function(el) {
20838 parent = el.offsetParent;
20841 parent = el.offsetParent;
20852 * Returns a Region object containing the drag and drop element's position
20853 * and size, including the padding configured for it
20854 * @method getLocation
20855 * @param {DragDrop} oDD the drag and drop object to get the
20857 * @return {Roo.lib.Region} a Region object representing the total area
20858 * the element occupies, including any padding
20859 * the instance is configured for.
20862 getLocation: function(oDD) {
20863 if (! this.isTypeOfDD(oDD)) {
20867 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
20870 pos= Roo.lib.Dom.getXY(el);
20878 x2 = x1 + el.offsetWidth;
20880 y2 = y1 + el.offsetHeight;
20882 t = y1 - oDD.padding[0];
20883 r = x2 + oDD.padding[1];
20884 b = y2 + oDD.padding[2];
20885 l = x1 - oDD.padding[3];
20887 return new Roo.lib.Region( t, r, b, l );
20891 * Checks the cursor location to see if it over the target
20892 * @method isOverTarget
20893 * @param {Roo.lib.Point} pt The point to evaluate
20894 * @param {DragDrop} oTarget the DragDrop object we are inspecting
20895 * @return {boolean} true if the mouse is over the target
20899 isOverTarget: function(pt, oTarget, intersect) {
20900 // use cache if available
20901 var loc = this.locationCache[oTarget.id];
20902 if (!loc || !this.useCache) {
20903 loc = this.getLocation(oTarget);
20904 this.locationCache[oTarget.id] = loc;
20912 oTarget.cursorIsOver = loc.contains( pt );
20914 // DragDrop is using this as a sanity check for the initial mousedown
20915 // in this case we are done. In POINT mode, if the drag obj has no
20916 // contraints, we are also done. Otherwise we need to evaluate the
20917 // location of the target as related to the actual location of the
20918 // dragged element.
20919 var dc = this.dragCurrent;
20920 if (!dc || !dc.getTargetCoord ||
20921 (!intersect && !dc.constrainX && !dc.constrainY)) {
20922 return oTarget.cursorIsOver;
20925 oTarget.overlap = null;
20927 // Get the current location of the drag element, this is the
20928 // location of the mouse event less the delta that represents
20929 // where the original mousedown happened on the element. We
20930 // need to consider constraints and ticks as well.
20931 var pos = dc.getTargetCoord(pt.x, pt.y);
20933 var el = dc.getDragEl();
20934 var curRegion = new Roo.lib.Region( pos.y,
20935 pos.x + el.offsetWidth,
20936 pos.y + el.offsetHeight,
20939 var overlap = curRegion.intersect(loc);
20942 oTarget.overlap = overlap;
20943 return (intersect) ? true : oTarget.cursorIsOver;
20950 * unload event handler
20951 * @method _onUnload
20955 _onUnload: function(e, me) {
20956 Roo.dd.DragDropMgr.unregAll();
20960 * Cleans up the drag and drop events and objects.
20965 unregAll: function() {
20967 if (this.dragCurrent) {
20969 this.dragCurrent = null;
20972 this._execOnAll("unreg", []);
20974 for (i in this.elementCache) {
20975 delete this.elementCache[i];
20978 this.elementCache = {};
20983 * A cache of DOM elements
20984 * @property elementCache
20991 * Get the wrapper for the DOM element specified
20992 * @method getElWrapper
20993 * @param {String} id the id of the element to get
20994 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
20996 * @deprecated This wrapper isn't that useful
20999 getElWrapper: function(id) {
21000 var oWrapper = this.elementCache[id];
21001 if (!oWrapper || !oWrapper.el) {
21002 oWrapper = this.elementCache[id] =
21003 new this.ElementWrapper(Roo.getDom(id));
21009 * Returns the actual DOM element
21010 * @method getElement
21011 * @param {String} id the id of the elment to get
21012 * @return {Object} The element
21013 * @deprecated use Roo.getDom instead
21016 getElement: function(id) {
21017 return Roo.getDom(id);
21021 * Returns the style property for the DOM element (i.e.,
21022 * document.getElById(id).style)
21024 * @param {String} id the id of the elment to get
21025 * @return {Object} The style property of the element
21026 * @deprecated use Roo.getDom instead
21029 getCss: function(id) {
21030 var el = Roo.getDom(id);
21031 return (el) ? el.style : null;
21035 * Inner class for cached elements
21036 * @class DragDropMgr.ElementWrapper
21041 ElementWrapper: function(el) {
21046 this.el = el || null;
21051 this.id = this.el && el.id;
21053 * A reference to the style property
21056 this.css = this.el && el.style;
21060 * Returns the X position of an html element
21062 * @param el the element for which to get the position
21063 * @return {int} the X coordinate
21065 * @deprecated use Roo.lib.Dom.getX instead
21068 getPosX: function(el) {
21069 return Roo.lib.Dom.getX(el);
21073 * Returns the Y position of an html element
21075 * @param el the element for which to get the position
21076 * @return {int} the Y coordinate
21077 * @deprecated use Roo.lib.Dom.getY instead
21080 getPosY: function(el) {
21081 return Roo.lib.Dom.getY(el);
21085 * Swap two nodes. In IE, we use the native method, for others we
21086 * emulate the IE behavior
21088 * @param n1 the first node to swap
21089 * @param n2 the other node to swap
21092 swapNode: function(n1, n2) {
21096 var p = n2.parentNode;
21097 var s = n2.nextSibling;
21100 p.insertBefore(n1, n2);
21101 } else if (n2 == n1.nextSibling) {
21102 p.insertBefore(n2, n1);
21104 n1.parentNode.replaceChild(n2, n1);
21105 p.insertBefore(n1, s);
21111 * Returns the current scroll position
21112 * @method getScroll
21116 getScroll: function () {
21117 var t, l, dde=document.documentElement, db=document.body;
21118 if (dde && (dde.scrollTop || dde.scrollLeft)) {
21120 l = dde.scrollLeft;
21127 return { top: t, left: l };
21131 * Returns the specified element style property
21133 * @param {HTMLElement} el the element
21134 * @param {string} styleProp the style property
21135 * @return {string} The value of the style property
21136 * @deprecated use Roo.lib.Dom.getStyle
21139 getStyle: function(el, styleProp) {
21140 return Roo.fly(el).getStyle(styleProp);
21144 * Gets the scrollTop
21145 * @method getScrollTop
21146 * @return {int} the document's scrollTop
21149 getScrollTop: function () { return this.getScroll().top; },
21152 * Gets the scrollLeft
21153 * @method getScrollLeft
21154 * @return {int} the document's scrollTop
21157 getScrollLeft: function () { return this.getScroll().left; },
21160 * Sets the x/y position of an element to the location of the
21163 * @param {HTMLElement} moveEl The element to move
21164 * @param {HTMLElement} targetEl The position reference element
21167 moveToEl: function (moveEl, targetEl) {
21168 var aCoord = Roo.lib.Dom.getXY(targetEl);
21169 Roo.lib.Dom.setXY(moveEl, aCoord);
21173 * Numeric array sort function
21174 * @method numericSort
21177 numericSort: function(a, b) { return (a - b); },
21181 * @property _timeoutCount
21188 * Trying to make the load order less important. Without this we get
21189 * an error if this file is loaded before the Event Utility.
21190 * @method _addListeners
21194 _addListeners: function() {
21195 var DDM = Roo.dd.DDM;
21196 if ( Roo.lib.Event && document ) {
21199 if (DDM._timeoutCount > 2000) {
21201 setTimeout(DDM._addListeners, 10);
21202 if (document && document.body) {
21203 DDM._timeoutCount += 1;
21210 * Recursively searches the immediate parent and all child nodes for
21211 * the handle element in order to determine wheter or not it was
21213 * @method handleWasClicked
21214 * @param node the html element to inspect
21217 handleWasClicked: function(node, id) {
21218 if (this.isHandle(id, node.id)) {
21221 // check to see if this is a text node child of the one we want
21222 var p = node.parentNode;
21225 if (this.isHandle(id, p.id)) {
21240 // shorter alias, save a few bytes
21241 Roo.dd.DDM = Roo.dd.DragDropMgr;
21242 Roo.dd.DDM._addListeners();
21246 * Ext JS Library 1.1.1
21247 * Copyright(c) 2006-2007, Ext JS, LLC.
21249 * Originally Released Under LGPL - original licence link has changed is not relivant.
21252 * <script type="text/javascript">
21257 * A DragDrop implementation where the linked element follows the
21258 * mouse cursor during a drag.
21259 * @extends Roo.dd.DragDrop
21261 * @param {String} id the id of the linked element
21262 * @param {String} sGroup the group of related DragDrop items
21263 * @param {object} config an object containing configurable attributes
21264 * Valid properties for DD:
21267 Roo.dd.DD = function(id, sGroup, config) {
21269 this.init(id, sGroup, config);
21273 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
21276 * When set to true, the utility automatically tries to scroll the browser
21277 * window wehn a drag and drop element is dragged near the viewport boundary.
21278 * Defaults to true.
21285 * Sets the pointer offset to the distance between the linked element's top
21286 * left corner and the location the element was clicked
21287 * @method autoOffset
21288 * @param {int} iPageX the X coordinate of the click
21289 * @param {int} iPageY the Y coordinate of the click
21291 autoOffset: function(iPageX, iPageY) {
21292 var x = iPageX - this.startPageX;
21293 var y = iPageY - this.startPageY;
21294 this.setDelta(x, y);
21298 * Sets the pointer offset. You can call this directly to force the
21299 * offset to be in a particular location (e.g., pass in 0,0 to set it
21300 * to the center of the object)
21302 * @param {int} iDeltaX the distance from the left
21303 * @param {int} iDeltaY the distance from the top
21305 setDelta: function(iDeltaX, iDeltaY) {
21306 this.deltaX = iDeltaX;
21307 this.deltaY = iDeltaY;
21311 * Sets the drag element to the location of the mousedown or click event,
21312 * maintaining the cursor location relative to the location on the element
21313 * that was clicked. Override this if you want to place the element in a
21314 * location other than where the cursor is.
21315 * @method setDragElPos
21316 * @param {int} iPageX the X coordinate of the mousedown or drag event
21317 * @param {int} iPageY the Y coordinate of the mousedown or drag event
21319 setDragElPos: function(iPageX, iPageY) {
21320 // the first time we do this, we are going to check to make sure
21321 // the element has css positioning
21323 var el = this.getDragEl();
21324 this.alignElWithMouse(el, iPageX, iPageY);
21328 * Sets the element to the location of the mousedown or click event,
21329 * maintaining the cursor location relative to the location on the element
21330 * that was clicked. Override this if you want to place the element in a
21331 * location other than where the cursor is.
21332 * @method alignElWithMouse
21333 * @param {HTMLElement} el the element to move
21334 * @param {int} iPageX the X coordinate of the mousedown or drag event
21335 * @param {int} iPageY the Y coordinate of the mousedown or drag event
21337 alignElWithMouse: function(el, iPageX, iPageY) {
21338 var oCoord = this.getTargetCoord(iPageX, iPageY);
21339 var fly = el.dom ? el : Roo.fly(el);
21340 if (!this.deltaSetXY) {
21341 var aCoord = [oCoord.x, oCoord.y];
21343 var newLeft = fly.getLeft(true);
21344 var newTop = fly.getTop(true);
21345 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
21347 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
21350 this.cachePosition(oCoord.x, oCoord.y);
21351 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
21356 * Saves the most recent position so that we can reset the constraints and
21357 * tick marks on-demand. We need to know this so that we can calculate the
21358 * number of pixels the element is offset from its original position.
21359 * @method cachePosition
21360 * @param iPageX the current x position (optional, this just makes it so we
21361 * don't have to look it up again)
21362 * @param iPageY the current y position (optional, this just makes it so we
21363 * don't have to look it up again)
21365 cachePosition: function(iPageX, iPageY) {
21367 this.lastPageX = iPageX;
21368 this.lastPageY = iPageY;
21370 var aCoord = Roo.lib.Dom.getXY(this.getEl());
21371 this.lastPageX = aCoord[0];
21372 this.lastPageY = aCoord[1];
21377 * Auto-scroll the window if the dragged object has been moved beyond the
21378 * visible window boundary.
21379 * @method autoScroll
21380 * @param {int} x the drag element's x position
21381 * @param {int} y the drag element's y position
21382 * @param {int} h the height of the drag element
21383 * @param {int} w the width of the drag element
21386 autoScroll: function(x, y, h, w) {
21389 // The client height
21390 var clientH = Roo.lib.Dom.getViewWidth();
21392 // The client width
21393 var clientW = Roo.lib.Dom.getViewHeight();
21395 // The amt scrolled down
21396 var st = this.DDM.getScrollTop();
21398 // The amt scrolled right
21399 var sl = this.DDM.getScrollLeft();
21401 // Location of the bottom of the element
21404 // Location of the right of the element
21407 // The distance from the cursor to the bottom of the visible area,
21408 // adjusted so that we don't scroll if the cursor is beyond the
21409 // element drag constraints
21410 var toBot = (clientH + st - y - this.deltaY);
21412 // The distance from the cursor to the right of the visible area
21413 var toRight = (clientW + sl - x - this.deltaX);
21416 // How close to the edge the cursor must be before we scroll
21417 // var thresh = (document.all) ? 100 : 40;
21420 // How many pixels to scroll per autoscroll op. This helps to reduce
21421 // clunky scrolling. IE is more sensitive about this ... it needs this
21422 // value to be higher.
21423 var scrAmt = (document.all) ? 80 : 30;
21425 // Scroll down if we are near the bottom of the visible page and the
21426 // obj extends below the crease
21427 if ( bot > clientH && toBot < thresh ) {
21428 window.scrollTo(sl, st + scrAmt);
21431 // Scroll up if the window is scrolled down and the top of the object
21432 // goes above the top border
21433 if ( y < st && st > 0 && y - st < thresh ) {
21434 window.scrollTo(sl, st - scrAmt);
21437 // Scroll right if the obj is beyond the right border and the cursor is
21438 // near the border.
21439 if ( right > clientW && toRight < thresh ) {
21440 window.scrollTo(sl + scrAmt, st);
21443 // Scroll left if the window has been scrolled to the right and the obj
21444 // extends past the left border
21445 if ( x < sl && sl > 0 && x - sl < thresh ) {
21446 window.scrollTo(sl - scrAmt, st);
21452 * Finds the location the element should be placed if we want to move
21453 * it to where the mouse location less the click offset would place us.
21454 * @method getTargetCoord
21455 * @param {int} iPageX the X coordinate of the click
21456 * @param {int} iPageY the Y coordinate of the click
21457 * @return an object that contains the coordinates (Object.x and Object.y)
21460 getTargetCoord: function(iPageX, iPageY) {
21463 var x = iPageX - this.deltaX;
21464 var y = iPageY - this.deltaY;
21466 if (this.constrainX) {
21467 if (x < this.minX) { x = this.minX; }
21468 if (x > this.maxX) { x = this.maxX; }
21471 if (this.constrainY) {
21472 if (y < this.minY) { y = this.minY; }
21473 if (y > this.maxY) { y = this.maxY; }
21476 x = this.getTick(x, this.xTicks);
21477 y = this.getTick(y, this.yTicks);
21484 * Sets up config options specific to this class. Overrides
21485 * Roo.dd.DragDrop, but all versions of this method through the
21486 * inheritance chain are called
21488 applyConfig: function() {
21489 Roo.dd.DD.superclass.applyConfig.call(this);
21490 this.scroll = (this.config.scroll !== false);
21494 * Event that fires prior to the onMouseDown event. Overrides
21497 b4MouseDown: function(e) {
21498 // this.resetConstraints();
21499 this.autoOffset(e.getPageX(),
21504 * Event that fires prior to the onDrag event. Overrides
21507 b4Drag: function(e) {
21508 this.setDragElPos(e.getPageX(),
21512 toString: function() {
21513 return ("DD " + this.id);
21516 //////////////////////////////////////////////////////////////////////////
21517 // Debugging ygDragDrop events that can be overridden
21518 //////////////////////////////////////////////////////////////////////////
21520 startDrag: function(x, y) {
21523 onDrag: function(e) {
21526 onDragEnter: function(e, id) {
21529 onDragOver: function(e, id) {
21532 onDragOut: function(e, id) {
21535 onDragDrop: function(e, id) {
21538 endDrag: function(e) {
21545 * Ext JS Library 1.1.1
21546 * Copyright(c) 2006-2007, Ext JS, LLC.
21548 * Originally Released Under LGPL - original licence link has changed is not relivant.
21551 * <script type="text/javascript">
21555 * @class Roo.dd.DDProxy
21556 * A DragDrop implementation that inserts an empty, bordered div into
21557 * the document that follows the cursor during drag operations. At the time of
21558 * the click, the frame div is resized to the dimensions of the linked html
21559 * element, and moved to the exact location of the linked element.
21561 * References to the "frame" element refer to the single proxy element that
21562 * was created to be dragged in place of all DDProxy elements on the
21565 * @extends Roo.dd.DD
21567 * @param {String} id the id of the linked html element
21568 * @param {String} sGroup the group of related DragDrop objects
21569 * @param {object} config an object containing configurable attributes
21570 * Valid properties for DDProxy in addition to those in DragDrop:
21571 * resizeFrame, centerFrame, dragElId
21573 Roo.dd.DDProxy = function(id, sGroup, config) {
21575 this.init(id, sGroup, config);
21581 * The default drag frame div id
21582 * @property Roo.dd.DDProxy.dragElId
21586 Roo.dd.DDProxy.dragElId = "ygddfdiv";
21588 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
21591 * By default we resize the drag frame to be the same size as the element
21592 * we want to drag (this is to get the frame effect). We can turn it off
21593 * if we want a different behavior.
21594 * @property resizeFrame
21600 * By default the frame is positioned exactly where the drag element is, so
21601 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
21602 * you do not have constraints on the obj is to have the drag frame centered
21603 * around the cursor. Set centerFrame to true for this effect.
21604 * @property centerFrame
21607 centerFrame: false,
21610 * Creates the proxy element if it does not yet exist
21611 * @method createFrame
21613 createFrame: function() {
21615 var body = document.body;
21617 if (!body || !body.firstChild) {
21618 setTimeout( function() { self.createFrame(); }, 50 );
21622 var div = this.getDragEl();
21625 div = document.createElement("div");
21626 div.id = this.dragElId;
21629 s.position = "absolute";
21630 s.visibility = "hidden";
21632 s.border = "2px solid #aaa";
21635 // appendChild can blow up IE if invoked prior to the window load event
21636 // while rendering a table. It is possible there are other scenarios
21637 // that would cause this to happen as well.
21638 body.insertBefore(div, body.firstChild);
21643 * Initialization for the drag frame element. Must be called in the
21644 * constructor of all subclasses
21645 * @method initFrame
21647 initFrame: function() {
21648 this.createFrame();
21651 applyConfig: function() {
21652 Roo.dd.DDProxy.superclass.applyConfig.call(this);
21654 this.resizeFrame = (this.config.resizeFrame !== false);
21655 this.centerFrame = (this.config.centerFrame);
21656 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
21660 * Resizes the drag frame to the dimensions of the clicked object, positions
21661 * it over the object, and finally displays it
21662 * @method showFrame
21663 * @param {int} iPageX X click position
21664 * @param {int} iPageY Y click position
21667 showFrame: function(iPageX, iPageY) {
21668 var el = this.getEl();
21669 var dragEl = this.getDragEl();
21670 var s = dragEl.style;
21672 this._resizeProxy();
21674 if (this.centerFrame) {
21675 this.setDelta( Math.round(parseInt(s.width, 10)/2),
21676 Math.round(parseInt(s.height, 10)/2) );
21679 this.setDragElPos(iPageX, iPageY);
21681 Roo.fly(dragEl).show();
21685 * The proxy is automatically resized to the dimensions of the linked
21686 * element when a drag is initiated, unless resizeFrame is set to false
21687 * @method _resizeProxy
21690 _resizeProxy: function() {
21691 if (this.resizeFrame) {
21692 var el = this.getEl();
21693 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
21697 // overrides Roo.dd.DragDrop
21698 b4MouseDown: function(e) {
21699 var x = e.getPageX();
21700 var y = e.getPageY();
21701 this.autoOffset(x, y);
21702 this.setDragElPos(x, y);
21705 // overrides Roo.dd.DragDrop
21706 b4StartDrag: function(x, y) {
21707 // show the drag frame
21708 this.showFrame(x, y);
21711 // overrides Roo.dd.DragDrop
21712 b4EndDrag: function(e) {
21713 Roo.fly(this.getDragEl()).hide();
21716 // overrides Roo.dd.DragDrop
21717 // By default we try to move the element to the last location of the frame.
21718 // This is so that the default behavior mirrors that of Roo.dd.DD.
21719 endDrag: function(e) {
21721 var lel = this.getEl();
21722 var del = this.getDragEl();
21724 // Show the drag frame briefly so we can get its position
21725 del.style.visibility = "";
21728 // Hide the linked element before the move to get around a Safari
21730 lel.style.visibility = "hidden";
21731 Roo.dd.DDM.moveToEl(lel, del);
21732 del.style.visibility = "hidden";
21733 lel.style.visibility = "";
21738 beforeMove : function(){
21742 afterDrag : function(){
21746 toString: function() {
21747 return ("DDProxy " + this.id);
21753 * Ext JS Library 1.1.1
21754 * Copyright(c) 2006-2007, Ext JS, LLC.
21756 * Originally Released Under LGPL - original licence link has changed is not relivant.
21759 * <script type="text/javascript">
21763 * @class Roo.dd.DDTarget
21764 * A DragDrop implementation that does not move, but can be a drop
21765 * target. You would get the same result by simply omitting implementation
21766 * for the event callbacks, but this way we reduce the processing cost of the
21767 * event listener and the callbacks.
21768 * @extends Roo.dd.DragDrop
21770 * @param {String} id the id of the element that is a drop target
21771 * @param {String} sGroup the group of related DragDrop objects
21772 * @param {object} config an object containing configurable attributes
21773 * Valid properties for DDTarget in addition to those in
21777 Roo.dd.DDTarget = function(id, sGroup, config) {
21779 this.initTarget(id, sGroup, config);
21781 if (config && (config.listeners || config.events)) {
21782 Roo.dd.DragDrop.superclass.constructor.call(this, {
21783 listeners : config.listeners || {},
21784 events : config.events || {}
21789 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
21790 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
21791 toString: function() {
21792 return ("DDTarget " + this.id);
21797 * Ext JS Library 1.1.1
21798 * Copyright(c) 2006-2007, Ext JS, LLC.
21800 * Originally Released Under LGPL - original licence link has changed is not relivant.
21803 * <script type="text/javascript">
21808 * @class Roo.dd.ScrollManager
21809 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
21810 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
21813 Roo.dd.ScrollManager = function(){
21814 var ddm = Roo.dd.DragDropMgr;
21821 var onStop = function(e){
21826 var triggerRefresh = function(){
21827 if(ddm.dragCurrent){
21828 ddm.refreshCache(ddm.dragCurrent.groups);
21832 var doScroll = function(){
21833 if(ddm.dragCurrent){
21834 var dds = Roo.dd.ScrollManager;
21836 if(proc.el.scroll(proc.dir, dds.increment)){
21840 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
21845 var clearProc = function(){
21847 clearInterval(proc.id);
21854 var startProc = function(el, dir){
21855 Roo.log('scroll startproc');
21859 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
21862 var onFire = function(e, isDrop){
21864 if(isDrop || !ddm.dragCurrent){ return; }
21865 var dds = Roo.dd.ScrollManager;
21866 if(!dragEl || dragEl != ddm.dragCurrent){
21867 dragEl = ddm.dragCurrent;
21868 // refresh regions on drag start
21869 dds.refreshCache();
21872 var xy = Roo.lib.Event.getXY(e);
21873 var pt = new Roo.lib.Point(xy[0], xy[1]);
21874 for(var id in els){
21875 var el = els[id], r = el._region;
21876 if(r && r.contains(pt) && el.isScrollable()){
21877 if(r.bottom - pt.y <= dds.thresh){
21879 startProc(el, "down");
21882 }else if(r.right - pt.x <= dds.thresh){
21884 startProc(el, "left");
21887 }else if(pt.y - r.top <= dds.thresh){
21889 startProc(el, "up");
21892 }else if(pt.x - r.left <= dds.thresh){
21894 startProc(el, "right");
21903 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
21904 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
21908 * Registers new overflow element(s) to auto scroll
21909 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
21911 register : function(el){
21912 if(el instanceof Array){
21913 for(var i = 0, len = el.length; i < len; i++) {
21914 this.register(el[i]);
21920 Roo.dd.ScrollManager.els = els;
21924 * Unregisters overflow element(s) so they are no longer scrolled
21925 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
21927 unregister : function(el){
21928 if(el instanceof Array){
21929 for(var i = 0, len = el.length; i < len; i++) {
21930 this.unregister(el[i]);
21939 * The number of pixels from the edge of a container the pointer needs to be to
21940 * trigger scrolling (defaults to 25)
21946 * The number of pixels to scroll in each scroll increment (defaults to 50)
21952 * The frequency of scrolls in milliseconds (defaults to 500)
21958 * True to animate the scroll (defaults to true)
21964 * The animation duration in seconds -
21965 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
21971 * Manually trigger a cache refresh.
21973 refreshCache : function(){
21974 for(var id in els){
21975 if(typeof els[id] == 'object'){ // for people extending the object prototype
21976 els[id]._region = els[id].getRegion();
21983 * Ext JS Library 1.1.1
21984 * Copyright(c) 2006-2007, Ext JS, LLC.
21986 * Originally Released Under LGPL - original licence link has changed is not relivant.
21989 * <script type="text/javascript">
21994 * @class Roo.dd.Registry
21995 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
21996 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
21999 Roo.dd.Registry = function(){
22002 var autoIdSeed = 0;
22004 var getId = function(el, autogen){
22005 if(typeof el == "string"){
22009 if(!id && autogen !== false){
22010 id = "roodd-" + (++autoIdSeed);
22018 * Register a drag drop element
22019 * @param {String|HTMLElement} element The id or DOM node to register
22020 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
22021 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
22022 * knows how to interpret, plus there are some specific properties known to the Registry that should be
22023 * populated in the data object (if applicable):
22025 Value Description<br />
22026 --------- ------------------------------------------<br />
22027 handles Array of DOM nodes that trigger dragging<br />
22028 for the element being registered<br />
22029 isHandle True if the element passed in triggers<br />
22030 dragging itself, else false
22033 register : function(el, data){
22035 if(typeof el == "string"){
22036 el = document.getElementById(el);
22039 elements[getId(el)] = data;
22040 if(data.isHandle !== false){
22041 handles[data.ddel.id] = data;
22044 var hs = data.handles;
22045 for(var i = 0, len = hs.length; i < len; i++){
22046 handles[getId(hs[i])] = data;
22052 * Unregister a drag drop element
22053 * @param {String|HTMLElement} element The id or DOM node to unregister
22055 unregister : function(el){
22056 var id = getId(el, false);
22057 var data = elements[id];
22059 delete elements[id];
22061 var hs = data.handles;
22062 for(var i = 0, len = hs.length; i < len; i++){
22063 delete handles[getId(hs[i], false)];
22070 * Returns the handle registered for a DOM Node by id
22071 * @param {String|HTMLElement} id The DOM node or id to look up
22072 * @return {Object} handle The custom handle data
22074 getHandle : function(id){
22075 if(typeof id != "string"){ // must be element?
22078 return handles[id];
22082 * Returns the handle that is registered for the DOM node that is the target of the event
22083 * @param {Event} e The event
22084 * @return {Object} handle The custom handle data
22086 getHandleFromEvent : function(e){
22087 var t = Roo.lib.Event.getTarget(e);
22088 return t ? handles[t.id] : null;
22092 * Returns a custom data object that is registered for a DOM node by id
22093 * @param {String|HTMLElement} id The DOM node or id to look up
22094 * @return {Object} data The custom data
22096 getTarget : function(id){
22097 if(typeof id != "string"){ // must be element?
22100 return elements[id];
22104 * Returns a custom data object that is registered for the DOM node that is the target of the event
22105 * @param {Event} e The event
22106 * @return {Object} data The custom data
22108 getTargetFromEvent : function(e){
22109 var t = Roo.lib.Event.getTarget(e);
22110 return t ? elements[t.id] || handles[t.id] : null;
22115 * Ext JS Library 1.1.1
22116 * Copyright(c) 2006-2007, Ext JS, LLC.
22118 * Originally Released Under LGPL - original licence link has changed is not relivant.
22121 * <script type="text/javascript">
22126 * @class Roo.dd.StatusProxy
22127 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
22128 * default drag proxy used by all Roo.dd components.
22130 * @param {Object} config
22132 Roo.dd.StatusProxy = function(config){
22133 Roo.apply(this, config);
22134 this.id = this.id || Roo.id();
22135 this.el = new Roo.Layer({
22137 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
22138 {tag: "div", cls: "x-dd-drop-icon"},
22139 {tag: "div", cls: "x-dd-drag-ghost"}
22142 shadow: !config || config.shadow !== false
22144 this.ghost = Roo.get(this.el.dom.childNodes[1]);
22145 this.dropStatus = this.dropNotAllowed;
22148 Roo.dd.StatusProxy.prototype = {
22150 * @cfg {String} dropAllowed
22151 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
22153 dropAllowed : "x-dd-drop-ok",
22155 * @cfg {String} dropNotAllowed
22156 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
22158 dropNotAllowed : "x-dd-drop-nodrop",
22161 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
22162 * over the current target element.
22163 * @param {String} cssClass The css class for the new drop status indicator image
22165 setStatus : function(cssClass){
22166 cssClass = cssClass || this.dropNotAllowed;
22167 if(this.dropStatus != cssClass){
22168 this.el.replaceClass(this.dropStatus, cssClass);
22169 this.dropStatus = cssClass;
22174 * Resets the status indicator to the default dropNotAllowed value
22175 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
22177 reset : function(clearGhost){
22178 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
22179 this.dropStatus = this.dropNotAllowed;
22181 this.ghost.update("");
22186 * Updates the contents of the ghost element
22187 * @param {String} html The html that will replace the current innerHTML of the ghost element
22189 update : function(html){
22190 if(typeof html == "string"){
22191 this.ghost.update(html);
22193 this.ghost.update("");
22194 html.style.margin = "0";
22195 this.ghost.dom.appendChild(html);
22197 // ensure float = none set?? cant remember why though.
22198 var el = this.ghost.dom.firstChild;
22200 Roo.fly(el).setStyle('float', 'none');
22205 * Returns the underlying proxy {@link Roo.Layer}
22206 * @return {Roo.Layer} el
22208 getEl : function(){
22213 * Returns the ghost element
22214 * @return {Roo.Element} el
22216 getGhost : function(){
22222 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
22224 hide : function(clear){
22232 * Stops the repair animation if it's currently running
22235 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
22241 * Displays this proxy
22248 * Force the Layer to sync its shadow and shim positions to the element
22255 * Causes the proxy to return to its position of origin via an animation. Should be called after an
22256 * invalid drop operation by the item being dragged.
22257 * @param {Array} xy The XY position of the element ([x, y])
22258 * @param {Function} callback The function to call after the repair is complete
22259 * @param {Object} scope The scope in which to execute the callback
22261 repair : function(xy, callback, scope){
22262 this.callback = callback;
22263 this.scope = scope;
22264 if(xy && this.animRepair !== false){
22265 this.el.addClass("x-dd-drag-repair");
22266 this.el.hideUnders(true);
22267 this.anim = this.el.shift({
22268 duration: this.repairDuration || .5,
22272 callback: this.afterRepair,
22276 this.afterRepair();
22281 afterRepair : function(){
22283 if(typeof this.callback == "function"){
22284 this.callback.call(this.scope || this);
22286 this.callback = null;
22291 * Ext JS Library 1.1.1
22292 * Copyright(c) 2006-2007, Ext JS, LLC.
22294 * Originally Released Under LGPL - original licence link has changed is not relivant.
22297 * <script type="text/javascript">
22301 * @class Roo.dd.DragSource
22302 * @extends Roo.dd.DDProxy
22303 * A simple class that provides the basic implementation needed to make any element draggable.
22305 * @param {String/HTMLElement/Element} el The container element
22306 * @param {Object} config
22308 Roo.dd.DragSource = function(el, config){
22309 this.el = Roo.get(el);
22310 this.dragData = {};
22312 Roo.apply(this, config);
22315 this.proxy = new Roo.dd.StatusProxy();
22318 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
22319 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
22321 this.dragging = false;
22324 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
22326 * @cfg {String} dropAllowed
22327 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
22329 dropAllowed : "x-dd-drop-ok",
22331 * @cfg {String} dropNotAllowed
22332 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
22334 dropNotAllowed : "x-dd-drop-nodrop",
22337 * Returns the data object associated with this drag source
22338 * @return {Object} data An object containing arbitrary data
22340 getDragData : function(e){
22341 return this.dragData;
22345 onDragEnter : function(e, id){
22346 var target = Roo.dd.DragDropMgr.getDDById(id);
22347 this.cachedTarget = target;
22348 if(this.beforeDragEnter(target, e, id) !== false){
22349 if(target.isNotifyTarget){
22350 var status = target.notifyEnter(this, e, this.dragData);
22351 this.proxy.setStatus(status);
22353 this.proxy.setStatus(this.dropAllowed);
22356 if(this.afterDragEnter){
22358 * An empty function by default, but provided so that you can perform a custom action
22359 * when the dragged item enters the drop target by providing an implementation.
22360 * @param {Roo.dd.DragDrop} target The drop target
22361 * @param {Event} e The event object
22362 * @param {String} id The id of the dragged element
22363 * @method afterDragEnter
22365 this.afterDragEnter(target, e, id);
22371 * An empty function by default, but provided so that you can perform a custom action
22372 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
22373 * @param {Roo.dd.DragDrop} target The drop target
22374 * @param {Event} e The event object
22375 * @param {String} id The id of the dragged element
22376 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
22378 beforeDragEnter : function(target, e, id){
22383 alignElWithMouse: function() {
22384 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
22389 onDragOver : function(e, id){
22390 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
22391 if(this.beforeDragOver(target, e, id) !== false){
22392 if(target.isNotifyTarget){
22393 var status = target.notifyOver(this, e, this.dragData);
22394 this.proxy.setStatus(status);
22397 if(this.afterDragOver){
22399 * An empty function by default, but provided so that you can perform a custom action
22400 * while the dragged item is over the drop target by providing an implementation.
22401 * @param {Roo.dd.DragDrop} target The drop target
22402 * @param {Event} e The event object
22403 * @param {String} id The id of the dragged element
22404 * @method afterDragOver
22406 this.afterDragOver(target, e, id);
22412 * An empty function by default, but provided so that you can perform a custom action
22413 * while the dragged item is over the drop target and optionally cancel the onDragOver.
22414 * @param {Roo.dd.DragDrop} target The drop target
22415 * @param {Event} e The event object
22416 * @param {String} id The id of the dragged element
22417 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
22419 beforeDragOver : function(target, e, id){
22424 onDragOut : function(e, id){
22425 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
22426 if(this.beforeDragOut(target, e, id) !== false){
22427 if(target.isNotifyTarget){
22428 target.notifyOut(this, e, this.dragData);
22430 this.proxy.reset();
22431 if(this.afterDragOut){
22433 * An empty function by default, but provided so that you can perform a custom action
22434 * after the dragged item is dragged out of the target without dropping.
22435 * @param {Roo.dd.DragDrop} target The drop target
22436 * @param {Event} e The event object
22437 * @param {String} id The id of the dragged element
22438 * @method afterDragOut
22440 this.afterDragOut(target, e, id);
22443 this.cachedTarget = null;
22447 * An empty function by default, but provided so that you can perform a custom action before the dragged
22448 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
22449 * @param {Roo.dd.DragDrop} target The drop target
22450 * @param {Event} e The event object
22451 * @param {String} id The id of the dragged element
22452 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
22454 beforeDragOut : function(target, e, id){
22459 onDragDrop : function(e, id){
22460 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
22461 if(this.beforeDragDrop(target, e, id) !== false){
22462 if(target.isNotifyTarget){
22463 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
22464 this.onValidDrop(target, e, id);
22466 this.onInvalidDrop(target, e, id);
22469 this.onValidDrop(target, e, id);
22472 if(this.afterDragDrop){
22474 * An empty function by default, but provided so that you can perform a custom action
22475 * after a valid drag drop has occurred by providing an implementation.
22476 * @param {Roo.dd.DragDrop} target The drop target
22477 * @param {Event} e The event object
22478 * @param {String} id The id of the dropped element
22479 * @method afterDragDrop
22481 this.afterDragDrop(target, e, id);
22484 delete this.cachedTarget;
22488 * An empty function by default, but provided so that you can perform a custom action before the dragged
22489 * item is dropped onto the target and optionally cancel the onDragDrop.
22490 * @param {Roo.dd.DragDrop} target The drop target
22491 * @param {Event} e The event object
22492 * @param {String} id The id of the dragged element
22493 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
22495 beforeDragDrop : function(target, e, id){
22500 onValidDrop : function(target, e, id){
22502 if(this.afterValidDrop){
22504 * An empty function by default, but provided so that you can perform a custom action
22505 * after a valid drop has occurred by providing an implementation.
22506 * @param {Object} target The target DD
22507 * @param {Event} e The event object
22508 * @param {String} id The id of the dropped element
22509 * @method afterInvalidDrop
22511 this.afterValidDrop(target, e, id);
22516 getRepairXY : function(e, data){
22517 return this.el.getXY();
22521 onInvalidDrop : function(target, e, id){
22522 this.beforeInvalidDrop(target, e, id);
22523 if(this.cachedTarget){
22524 if(this.cachedTarget.isNotifyTarget){
22525 this.cachedTarget.notifyOut(this, e, this.dragData);
22527 this.cacheTarget = null;
22529 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
22531 if(this.afterInvalidDrop){
22533 * An empty function by default, but provided so that you can perform a custom action
22534 * after an invalid drop has occurred by providing an implementation.
22535 * @param {Event} e The event object
22536 * @param {String} id The id of the dropped element
22537 * @method afterInvalidDrop
22539 this.afterInvalidDrop(e, id);
22544 afterRepair : function(){
22546 this.el.highlight(this.hlColor || "c3daf9");
22548 this.dragging = false;
22552 * An empty function by default, but provided so that you can perform a custom action after an invalid
22553 * drop has occurred.
22554 * @param {Roo.dd.DragDrop} target The drop target
22555 * @param {Event} e The event object
22556 * @param {String} id The id of the dragged element
22557 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
22559 beforeInvalidDrop : function(target, e, id){
22564 handleMouseDown : function(e){
22565 if(this.dragging) {
22568 var data = this.getDragData(e);
22569 if(data && this.onBeforeDrag(data, e) !== false){
22570 this.dragData = data;
22572 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
22577 * An empty function by default, but provided so that you can perform a custom action before the initial
22578 * drag event begins and optionally cancel it.
22579 * @param {Object} data An object containing arbitrary data to be shared with drop targets
22580 * @param {Event} e The event object
22581 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
22583 onBeforeDrag : function(data, e){
22588 * An empty function by default, but provided so that you can perform a custom action once the initial
22589 * drag event has begun. The drag cannot be canceled from this function.
22590 * @param {Number} x The x position of the click on the dragged object
22591 * @param {Number} y The y position of the click on the dragged object
22593 onStartDrag : Roo.emptyFn,
22595 // private - YUI override
22596 startDrag : function(x, y){
22597 this.proxy.reset();
22598 this.dragging = true;
22599 this.proxy.update("");
22600 this.onInitDrag(x, y);
22605 onInitDrag : function(x, y){
22606 var clone = this.el.dom.cloneNode(true);
22607 clone.id = Roo.id(); // prevent duplicate ids
22608 this.proxy.update(clone);
22609 this.onStartDrag(x, y);
22614 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
22615 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
22617 getProxy : function(){
22622 * Hides the drag source's {@link Roo.dd.StatusProxy}
22624 hideProxy : function(){
22626 this.proxy.reset(true);
22627 this.dragging = false;
22631 triggerCacheRefresh : function(){
22632 Roo.dd.DDM.refreshCache(this.groups);
22635 // private - override to prevent hiding
22636 b4EndDrag: function(e) {
22639 // private - override to prevent moving
22640 endDrag : function(e){
22641 this.onEndDrag(this.dragData, e);
22645 onEndDrag : function(data, e){
22648 // private - pin to cursor
22649 autoOffset : function(x, y) {
22650 this.setDelta(-12, -20);
22654 * Ext JS Library 1.1.1
22655 * Copyright(c) 2006-2007, Ext JS, LLC.
22657 * Originally Released Under LGPL - original licence link has changed is not relivant.
22660 * <script type="text/javascript">
22665 * @class Roo.dd.DropTarget
22666 * @extends Roo.dd.DDTarget
22667 * A simple class that provides the basic implementation needed to make any element a drop target that can have
22668 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
22670 * @param {String/HTMLElement/Element} el The container element
22671 * @param {Object} config
22673 Roo.dd.DropTarget = function(el, config){
22674 this.el = Roo.get(el);
22676 var listeners = false; ;
22677 if (config && config.listeners) {
22678 listeners= config.listeners;
22679 delete config.listeners;
22681 Roo.apply(this, config);
22683 if(this.containerScroll){
22684 Roo.dd.ScrollManager.register(this.el);
22688 * @scope Roo.dd.DropTarget
22693 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
22694 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
22695 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
22697 * IMPORTANT : it should set this.valid to true|false
22699 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22700 * @param {Event} e The event
22701 * @param {Object} data An object containing arbitrary data supplied by the drag source
22707 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
22708 * This method will be called on every mouse movement while the drag source is over the drop target.
22709 * This default implementation simply returns the dropAllowed config value.
22711 * IMPORTANT : it should set this.valid to true|false
22713 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22714 * @param {Event} e The event
22715 * @param {Object} data An object containing arbitrary data supplied by the drag source
22721 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
22722 * out of the target without dropping. This default implementation simply removes the CSS class specified by
22723 * overClass (if any) from the drop element.
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 once to notify this drop target that the dragged item has
22735 * been dropped on it. This method has no default implementation and returns false, so you must provide an
22736 * implementation that does something to process the drop event and returns true so that the drag source's
22737 * repair action does not run.
22739 * IMPORTANT : it should set this.success
22741 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22742 * @param {Event} e The event
22743 * @param {Object} data An object containing arbitrary data supplied by the drag source
22749 Roo.dd.DropTarget.superclass.constructor.call( this,
22751 this.ddGroup || this.group,
22754 listeners : listeners || {}
22762 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
22764 * @cfg {String} overClass
22765 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
22768 * @cfg {String} ddGroup
22769 * The drag drop group to handle drop events for
22773 * @cfg {String} dropAllowed
22774 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
22776 dropAllowed : "x-dd-drop-ok",
22778 * @cfg {String} dropNotAllowed
22779 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
22781 dropNotAllowed : "x-dd-drop-nodrop",
22783 * @cfg {boolean} success
22784 * set this after drop listener..
22788 * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
22789 * if the drop point is valid for over/enter..
22796 isNotifyTarget : true,
22801 notifyEnter : function(dd, e, data)
22804 this.fireEvent('enter', dd, e, data);
22805 if(this.overClass){
22806 this.el.addClass(this.overClass);
22808 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
22809 this.valid ? this.dropAllowed : this.dropNotAllowed
22816 notifyOver : function(dd, e, data)
22819 this.fireEvent('over', dd, e, data);
22820 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
22821 this.valid ? this.dropAllowed : this.dropNotAllowed
22828 notifyOut : function(dd, e, data)
22830 this.fireEvent('out', dd, e, data);
22831 if(this.overClass){
22832 this.el.removeClass(this.overClass);
22839 notifyDrop : function(dd, e, data)
22841 this.success = false;
22842 this.fireEvent('drop', dd, e, data);
22843 return this.success;
22847 * Ext JS Library 1.1.1
22848 * Copyright(c) 2006-2007, Ext JS, LLC.
22850 * Originally Released Under LGPL - original licence link has changed is not relivant.
22853 * <script type="text/javascript">
22858 * @class Roo.dd.DragZone
22859 * @extends Roo.dd.DragSource
22860 * This class provides a container DD instance that proxies for multiple child node sources.<br />
22861 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
22863 * @param {String/HTMLElement/Element} el The container element
22864 * @param {Object} config
22866 Roo.dd.DragZone = function(el, config){
22867 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
22868 if(this.containerScroll){
22869 Roo.dd.ScrollManager.register(this.el);
22873 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
22875 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
22876 * for auto scrolling during drag operations.
22879 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
22880 * method after a failed drop (defaults to "c3daf9" - light blue)
22884 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
22885 * for a valid target to drag based on the mouse down. Override this method
22886 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
22887 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
22888 * @param {EventObject} e The mouse down event
22889 * @return {Object} The dragData
22891 getDragData : function(e){
22892 return Roo.dd.Registry.getHandleFromEvent(e);
22896 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
22897 * this.dragData.ddel
22898 * @param {Number} x The x position of the click on the dragged object
22899 * @param {Number} y The y position of the click on the dragged object
22900 * @return {Boolean} true to continue the drag, false to cancel
22902 onInitDrag : function(x, y){
22903 this.proxy.update(this.dragData.ddel.cloneNode(true));
22904 this.onStartDrag(x, y);
22909 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
22911 afterRepair : function(){
22913 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
22915 this.dragging = false;
22919 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
22920 * the XY of this.dragData.ddel
22921 * @param {EventObject} e The mouse up event
22922 * @return {Array} The xy location (e.g. [100, 200])
22924 getRepairXY : function(e){
22925 return Roo.Element.fly(this.dragData.ddel).getXY();
22929 * Ext JS Library 1.1.1
22930 * Copyright(c) 2006-2007, Ext JS, LLC.
22932 * Originally Released Under LGPL - original licence link has changed is not relivant.
22935 * <script type="text/javascript">
22938 * @class Roo.dd.DropZone
22939 * @extends Roo.dd.DropTarget
22940 * This class provides a container DD instance that proxies for multiple child node targets.<br />
22941 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
22943 * @param {String/HTMLElement/Element} el The container element
22944 * @param {Object} config
22946 Roo.dd.DropZone = function(el, config){
22947 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
22950 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
22952 * Returns a custom data object associated with the DOM node that is the target of the event. By default
22953 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
22954 * provide your own custom lookup.
22955 * @param {Event} e The event
22956 * @return {Object} data The custom data
22958 getTargetFromEvent : function(e){
22959 return Roo.dd.Registry.getTargetFromEvent(e);
22963 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
22964 * that it has registered. This method has no default implementation and should be overridden to provide
22965 * node-specific processing if necessary.
22966 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22967 * {@link #getTargetFromEvent} for this node)
22968 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22969 * @param {Event} e The event
22970 * @param {Object} data An object containing arbitrary data supplied by the drag source
22972 onNodeEnter : function(n, dd, e, data){
22977 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
22978 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
22979 * overridden to provide the proper feedback.
22980 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22981 * {@link #getTargetFromEvent} for this node)
22982 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22983 * @param {Event} e The event
22984 * @param {Object} data An object containing arbitrary data supplied by the drag source
22985 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22986 * underlying {@link Roo.dd.StatusProxy} can be updated
22988 onNodeOver : function(n, dd, e, data){
22989 return this.dropAllowed;
22993 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
22994 * the drop node without dropping. This method has no default implementation and should be overridden to provide
22995 * node-specific processing if necessary.
22996 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22997 * {@link #getTargetFromEvent} for this node)
22998 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22999 * @param {Event} e The event
23000 * @param {Object} data An object containing arbitrary data supplied by the drag source
23002 onNodeOut : function(n, dd, e, data){
23007 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
23008 * the drop node. The default implementation returns false, so it should be overridden to provide the
23009 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
23010 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
23011 * {@link #getTargetFromEvent} for this node)
23012 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23013 * @param {Event} e The event
23014 * @param {Object} data An object containing arbitrary data supplied by the drag source
23015 * @return {Boolean} True if the drop was valid, else false
23017 onNodeDrop : function(n, dd, e, data){
23022 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
23023 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
23024 * it should be overridden to provide the proper feedback if necessary.
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
23028 * @return {String} status The CSS class that communicates the drop status back to the source so that the
23029 * underlying {@link Roo.dd.StatusProxy} can be updated
23031 onContainerOver : function(dd, e, data){
23032 return this.dropNotAllowed;
23036 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
23037 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
23038 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
23039 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
23040 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23041 * @param {Event} e The event
23042 * @param {Object} data An object containing arbitrary data supplied by the drag source
23043 * @return {Boolean} True if the drop was valid, else false
23045 onContainerDrop : function(dd, e, data){
23050 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
23051 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
23052 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
23053 * you should override this method and provide a custom implementation.
23054 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23055 * @param {Event} e The event
23056 * @param {Object} data An object containing arbitrary data supplied by the drag source
23057 * @return {String} status The CSS class that communicates the drop status back to the source so that the
23058 * underlying {@link Roo.dd.StatusProxy} can be updated
23060 notifyEnter : function(dd, e, data){
23061 return this.dropNotAllowed;
23065 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
23066 * This method will be called on every mouse movement while the drag source is over the drop zone.
23067 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
23068 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
23069 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
23070 * registered node, it will call {@link #onContainerOver}.
23071 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23072 * @param {Event} e The event
23073 * @param {Object} data An object containing arbitrary data supplied by the drag source
23074 * @return {String} status The CSS class that communicates the drop status back to the source so that the
23075 * underlying {@link Roo.dd.StatusProxy} can be updated
23077 notifyOver : function(dd, e, data){
23078 var n = this.getTargetFromEvent(e);
23079 if(!n){ // not over valid drop target
23080 if(this.lastOverNode){
23081 this.onNodeOut(this.lastOverNode, dd, e, data);
23082 this.lastOverNode = null;
23084 return this.onContainerOver(dd, e, data);
23086 if(this.lastOverNode != n){
23087 if(this.lastOverNode){
23088 this.onNodeOut(this.lastOverNode, dd, e, data);
23090 this.onNodeEnter(n, dd, e, data);
23091 this.lastOverNode = n;
23093 return this.onNodeOver(n, dd, e, data);
23097 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
23098 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
23099 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
23100 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
23101 * @param {Event} e The event
23102 * @param {Object} data An object containing arbitrary data supplied by the drag zone
23104 notifyOut : function(dd, e, data){
23105 if(this.lastOverNode){
23106 this.onNodeOut(this.lastOverNode, dd, e, data);
23107 this.lastOverNode = null;
23112 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
23113 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
23114 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
23115 * otherwise it will call {@link #onContainerDrop}.
23116 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23117 * @param {Event} e The event
23118 * @param {Object} data An object containing arbitrary data supplied by the drag source
23119 * @return {Boolean} True if the drop was valid, else false
23121 notifyDrop : function(dd, e, data){
23122 if(this.lastOverNode){
23123 this.onNodeOut(this.lastOverNode, dd, e, data);
23124 this.lastOverNode = null;
23126 var n = this.getTargetFromEvent(e);
23128 this.onNodeDrop(n, dd, e, data) :
23129 this.onContainerDrop(dd, e, data);
23133 triggerCacheRefresh : function(){
23134 Roo.dd.DDM.refreshCache(this.groups);
23138 * Ext JS Library 1.1.1
23139 * Copyright(c) 2006-2007, Ext JS, LLC.
23141 * Originally Released Under LGPL - original licence link has changed is not relivant.
23144 * <script type="text/javascript">
23149 * @class Roo.data.SortTypes
23151 * Defines the default sorting (casting?) comparison functions used when sorting data.
23153 Roo.data.SortTypes = {
23155 * Default sort that does nothing
23156 * @param {Mixed} s The value being converted
23157 * @return {Mixed} The comparison value
23159 none : function(s){
23164 * The regular expression used to strip tags
23168 stripTagsRE : /<\/?[^>]+>/gi,
23171 * Strips all HTML tags to sort on text only
23172 * @param {Mixed} s The value being converted
23173 * @return {String} The comparison value
23175 asText : function(s){
23176 return String(s).replace(this.stripTagsRE, "");
23180 * Strips all HTML tags to sort on text only - Case insensitive
23181 * @param {Mixed} s The value being converted
23182 * @return {String} The comparison value
23184 asUCText : function(s){
23185 return String(s).toUpperCase().replace(this.stripTagsRE, "");
23189 * Case insensitive string
23190 * @param {Mixed} s The value being converted
23191 * @return {String} The comparison value
23193 asUCString : function(s) {
23194 return String(s).toUpperCase();
23199 * @param {Mixed} s The value being converted
23200 * @return {Number} The comparison value
23202 asDate : function(s) {
23206 if(s instanceof Date){
23207 return s.getTime();
23209 return Date.parse(String(s));
23214 * @param {Mixed} s The value being converted
23215 * @return {Float} The comparison value
23217 asFloat : function(s) {
23218 var val = parseFloat(String(s).replace(/,/g, ""));
23227 * @param {Mixed} s The value being converted
23228 * @return {Number} The comparison value
23230 asInt : function(s) {
23231 var val = parseInt(String(s).replace(/,/g, ""));
23239 * Ext JS Library 1.1.1
23240 * Copyright(c) 2006-2007, Ext JS, LLC.
23242 * Originally Released Under LGPL - original licence link has changed is not relivant.
23245 * <script type="text/javascript">
23249 * @class Roo.data.Record
23250 * Instances of this class encapsulate both record <em>definition</em> information, and record
23251 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
23252 * to access Records cached in an {@link Roo.data.Store} object.<br>
23254 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
23255 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
23258 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
23260 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
23261 * {@link #create}. The parameters are the same.
23262 * @param {Array} data An associative Array of data values keyed by the field name.
23263 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
23264 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
23265 * not specified an integer id is generated.
23267 Roo.data.Record = function(data, id){
23268 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
23273 * Generate a constructor for a specific record layout.
23274 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
23275 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
23276 * Each field definition object may contain the following properties: <ul>
23277 * <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,
23278 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
23279 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
23280 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
23281 * is being used, then this is a string containing the javascript expression to reference the data relative to
23282 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
23283 * to the data item relative to the record element. If the mapping expression is the same as the field name,
23284 * this may be omitted.</p></li>
23285 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
23286 * <ul><li>auto (Default, implies no conversion)</li>
23291 * <li>date</li></ul></p></li>
23292 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
23293 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
23294 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
23295 * by the Reader into an object that will be stored in the Record. It is passed the
23296 * following parameters:<ul>
23297 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
23299 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
23301 * <br>usage:<br><pre><code>
23302 var TopicRecord = Roo.data.Record.create(
23303 {name: 'title', mapping: 'topic_title'},
23304 {name: 'author', mapping: 'username'},
23305 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
23306 {name: 'lastPost', mapping: 'post_time', type: 'date'},
23307 {name: 'lastPoster', mapping: 'user2'},
23308 {name: 'excerpt', mapping: 'post_text'}
23311 var myNewRecord = new TopicRecord({
23312 title: 'Do my job please',
23315 lastPost: new Date(),
23316 lastPoster: 'Animal',
23317 excerpt: 'No way dude!'
23319 myStore.add(myNewRecord);
23324 Roo.data.Record.create = function(o){
23325 var f = function(){
23326 f.superclass.constructor.apply(this, arguments);
23328 Roo.extend(f, Roo.data.Record);
23329 var p = f.prototype;
23330 p.fields = new Roo.util.MixedCollection(false, function(field){
23333 for(var i = 0, len = o.length; i < len; i++){
23334 p.fields.add(new Roo.data.Field(o[i]));
23336 f.getField = function(name){
23337 return p.fields.get(name);
23342 Roo.data.Record.AUTO_ID = 1000;
23343 Roo.data.Record.EDIT = 'edit';
23344 Roo.data.Record.REJECT = 'reject';
23345 Roo.data.Record.COMMIT = 'commit';
23347 Roo.data.Record.prototype = {
23349 * Readonly flag - true if this record has been modified.
23358 join : function(store){
23359 this.store = store;
23363 * Set the named field to the specified value.
23364 * @param {String} name The name of the field to set.
23365 * @param {Object} value The value to set the field to.
23367 set : function(name, value){
23368 if(this.data[name] == value){
23372 if(!this.modified){
23373 this.modified = {};
23375 if(typeof this.modified[name] == 'undefined'){
23376 this.modified[name] = this.data[name];
23378 this.data[name] = value;
23379 if(!this.editing && this.store){
23380 this.store.afterEdit(this);
23385 * Get the value of the named field.
23386 * @param {String} name The name of the field to get the value of.
23387 * @return {Object} The value of the field.
23389 get : function(name){
23390 return this.data[name];
23394 beginEdit : function(){
23395 this.editing = true;
23396 this.modified = {};
23400 cancelEdit : function(){
23401 this.editing = false;
23402 delete this.modified;
23406 endEdit : function(){
23407 this.editing = false;
23408 if(this.dirty && this.store){
23409 this.store.afterEdit(this);
23414 * Usually called by the {@link Roo.data.Store} which owns the Record.
23415 * Rejects all changes made to the Record since either creation, or the last commit operation.
23416 * Modified fields are reverted to their original values.
23418 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
23419 * of reject operations.
23421 reject : function(){
23422 var m = this.modified;
23424 if(typeof m[n] != "function"){
23425 this.data[n] = m[n];
23428 this.dirty = false;
23429 delete this.modified;
23430 this.editing = false;
23432 this.store.afterReject(this);
23437 * Usually called by the {@link Roo.data.Store} which owns the Record.
23438 * Commits all changes made to the Record since either creation, or the last commit operation.
23440 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
23441 * of commit operations.
23443 commit : function(){
23444 this.dirty = false;
23445 delete this.modified;
23446 this.editing = false;
23448 this.store.afterCommit(this);
23453 hasError : function(){
23454 return this.error != null;
23458 clearError : function(){
23463 * Creates a copy of this record.
23464 * @param {String} id (optional) A new record id if you don't want to use this record's id
23467 copy : function(newId) {
23468 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
23472 * Ext JS Library 1.1.1
23473 * Copyright(c) 2006-2007, Ext JS, LLC.
23475 * Originally Released Under LGPL - original licence link has changed is not relivant.
23478 * <script type="text/javascript">
23484 * @class Roo.data.Store
23485 * @extends Roo.util.Observable
23486 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
23487 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
23489 * 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
23490 * has no knowledge of the format of the data returned by the Proxy.<br>
23492 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
23493 * instances from the data object. These records are cached and made available through accessor functions.
23495 * Creates a new Store.
23496 * @param {Object} config A config object containing the objects needed for the Store to access data,
23497 * and read the data into Records.
23499 Roo.data.Store = function(config){
23500 this.data = new Roo.util.MixedCollection(false);
23501 this.data.getKey = function(o){
23504 this.baseParams = {};
23506 this.paramNames = {
23511 "multisort" : "_multisort"
23514 if(config && config.data){
23515 this.inlineData = config.data;
23516 delete config.data;
23519 Roo.apply(this, config);
23521 if(this.reader){ // reader passed
23522 this.reader = Roo.factory(this.reader, Roo.data);
23523 this.reader.xmodule = this.xmodule || false;
23524 if(!this.recordType){
23525 this.recordType = this.reader.recordType;
23527 if(this.reader.onMetaChange){
23528 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
23532 if(this.recordType){
23533 this.fields = this.recordType.prototype.fields;
23535 this.modified = [];
23539 * @event datachanged
23540 * Fires when the data cache has changed, and a widget which is using this Store
23541 * as a Record cache should refresh its view.
23542 * @param {Store} this
23544 datachanged : true,
23546 * @event metachange
23547 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
23548 * @param {Store} this
23549 * @param {Object} meta The JSON metadata
23554 * Fires when Records have been added to the Store
23555 * @param {Store} this
23556 * @param {Roo.data.Record[]} records The array of Records added
23557 * @param {Number} index The index at which the record(s) were added
23562 * Fires when a Record has been removed from the Store
23563 * @param {Store} this
23564 * @param {Roo.data.Record} record The Record that was removed
23565 * @param {Number} index The index at which the record was removed
23570 * Fires when a Record has been updated
23571 * @param {Store} this
23572 * @param {Roo.data.Record} record The Record that was updated
23573 * @param {String} operation The update operation being performed. Value may be one of:
23575 Roo.data.Record.EDIT
23576 Roo.data.Record.REJECT
23577 Roo.data.Record.COMMIT
23583 * Fires when the data cache has been cleared.
23584 * @param {Store} this
23588 * @event beforeload
23589 * Fires before a request is made for a new data object. If the beforeload handler returns false
23590 * the load action will be canceled.
23591 * @param {Store} this
23592 * @param {Object} options The loading options that were specified (see {@link #load} for details)
23596 * @event beforeloadadd
23597 * Fires after a new set of Records has been loaded.
23598 * @param {Store} this
23599 * @param {Roo.data.Record[]} records The Records that were loaded
23600 * @param {Object} options The loading options that were specified (see {@link #load} for details)
23602 beforeloadadd : true,
23605 * Fires after a new set of Records has been loaded, before they are added to the store.
23606 * @param {Store} this
23607 * @param {Roo.data.Record[]} records The Records that were loaded
23608 * @param {Object} options The loading options that were specified (see {@link #load} for details)
23609 * @params {Object} return from reader
23613 * @event loadexception
23614 * Fires if an exception occurs in the Proxy during loading.
23615 * Called with the signature of the Proxy's "loadexception" event.
23616 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
23619 * @param {Object} return from JsonData.reader() - success, totalRecords, records
23620 * @param {Object} load options
23621 * @param {Object} jsonData from your request (normally this contains the Exception)
23623 loadexception : true
23627 this.proxy = Roo.factory(this.proxy, Roo.data);
23628 this.proxy.xmodule = this.xmodule || false;
23629 this.relayEvents(this.proxy, ["loadexception"]);
23631 this.sortToggle = {};
23632 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
23634 Roo.data.Store.superclass.constructor.call(this);
23636 if(this.inlineData){
23637 this.loadData(this.inlineData);
23638 delete this.inlineData;
23642 Roo.extend(Roo.data.Store, Roo.util.Observable, {
23644 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
23645 * without a remote query - used by combo/forms at present.
23649 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
23652 * @cfg {Array} data Inline data to be loaded when the store is initialized.
23655 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
23656 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
23659 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
23660 * on any HTTP request
23663 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
23666 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
23670 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
23671 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
23673 remoteSort : false,
23676 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
23677 * loaded or when a record is removed. (defaults to false).
23679 pruneModifiedRecords : false,
23682 lastOptions : null,
23685 * Add Records to the Store and fires the add event.
23686 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
23688 add : function(records){
23689 records = [].concat(records);
23690 for(var i = 0, len = records.length; i < len; i++){
23691 records[i].join(this);
23693 var index = this.data.length;
23694 this.data.addAll(records);
23695 this.fireEvent("add", this, records, index);
23699 * Remove a Record from the Store and fires the remove event.
23700 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
23702 remove : function(record){
23703 var index = this.data.indexOf(record);
23704 this.data.removeAt(index);
23706 if(this.pruneModifiedRecords){
23707 this.modified.remove(record);
23709 this.fireEvent("remove", this, record, index);
23713 * Remove all Records from the Store and fires the clear event.
23715 removeAll : function(){
23717 if(this.pruneModifiedRecords){
23718 this.modified = [];
23720 this.fireEvent("clear", this);
23724 * Inserts Records to the Store at the given index and fires the add event.
23725 * @param {Number} index The start index at which to insert the passed Records.
23726 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
23728 insert : function(index, records){
23729 records = [].concat(records);
23730 for(var i = 0, len = records.length; i < len; i++){
23731 this.data.insert(index, records[i]);
23732 records[i].join(this);
23734 this.fireEvent("add", this, records, index);
23738 * Get the index within the cache of the passed Record.
23739 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
23740 * @return {Number} The index of the passed Record. Returns -1 if not found.
23742 indexOf : function(record){
23743 return this.data.indexOf(record);
23747 * Get the index within the cache of the Record with the passed id.
23748 * @param {String} id The id of the Record to find.
23749 * @return {Number} The index of the Record. Returns -1 if not found.
23751 indexOfId : function(id){
23752 return this.data.indexOfKey(id);
23756 * Get the Record with the specified id.
23757 * @param {String} id The id of the Record to find.
23758 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
23760 getById : function(id){
23761 return this.data.key(id);
23765 * Get the Record at the specified index.
23766 * @param {Number} index The index of the Record to find.
23767 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
23769 getAt : function(index){
23770 return this.data.itemAt(index);
23774 * Returns a range of Records between specified indices.
23775 * @param {Number} startIndex (optional) The starting index (defaults to 0)
23776 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
23777 * @return {Roo.data.Record[]} An array of Records
23779 getRange : function(start, end){
23780 return this.data.getRange(start, end);
23784 storeOptions : function(o){
23785 o = Roo.apply({}, o);
23788 this.lastOptions = o;
23792 * Loads the Record cache from the configured Proxy using the configured Reader.
23794 * If using remote paging, then the first load call must specify the <em>start</em>
23795 * and <em>limit</em> properties in the options.params property to establish the initial
23796 * position within the dataset, and the number of Records to cache on each read from the Proxy.
23798 * <strong>It is important to note that for remote data sources, loading is asynchronous,
23799 * and this call will return before the new data has been loaded. Perform any post-processing
23800 * in a callback function, or in a "load" event handler.</strong>
23802 * @param {Object} options An object containing properties which control loading options:<ul>
23803 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
23804 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
23805 * passed the following arguments:<ul>
23806 * <li>r : Roo.data.Record[]</li>
23807 * <li>options: Options object from the load call</li>
23808 * <li>success: Boolean success indicator</li></ul></li>
23809 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
23810 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
23813 load : function(options){
23814 options = options || {};
23815 if(this.fireEvent("beforeload", this, options) !== false){
23816 this.storeOptions(options);
23817 var p = Roo.apply(options.params || {}, this.baseParams);
23818 // if meta was not loaded from remote source.. try requesting it.
23819 if (!this.reader.metaFromRemote) {
23820 p._requestMeta = 1;
23822 if(this.sortInfo && this.remoteSort){
23823 var pn = this.paramNames;
23824 p[pn["sort"]] = this.sortInfo.field;
23825 p[pn["dir"]] = this.sortInfo.direction;
23827 if (this.multiSort) {
23828 var pn = this.paramNames;
23829 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
23832 this.proxy.load(p, this.reader, this.loadRecords, this, options);
23837 * Reloads the Record cache from the configured Proxy using the configured Reader and
23838 * the options from the last load operation performed.
23839 * @param {Object} options (optional) An object containing properties which may override the options
23840 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
23841 * the most recently used options are reused).
23843 reload : function(options){
23844 this.load(Roo.applyIf(options||{}, this.lastOptions));
23848 // Called as a callback by the Reader during a load operation.
23849 loadRecords : function(o, options, success){
23850 if(!o || success === false){
23851 if(success !== false){
23852 this.fireEvent("load", this, [], options, o);
23854 if(options.callback){
23855 options.callback.call(options.scope || this, [], options, false);
23859 // if data returned failure - throw an exception.
23860 if (o.success === false) {
23861 // show a message if no listener is registered.
23862 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
23863 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
23865 // loadmask wil be hooked into this..
23866 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
23869 var r = o.records, t = o.totalRecords || r.length;
23871 this.fireEvent("beforeloadadd", this, r, options, o);
23873 if(!options || options.add !== true){
23874 if(this.pruneModifiedRecords){
23875 this.modified = [];
23877 for(var i = 0, len = r.length; i < len; i++){
23881 this.data = this.snapshot;
23882 delete this.snapshot;
23885 this.data.addAll(r);
23886 this.totalLength = t;
23888 this.fireEvent("datachanged", this);
23890 this.totalLength = Math.max(t, this.data.length+r.length);
23894 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
23896 var e = new Roo.data.Record({});
23898 e.set(this.parent.displayField, this.parent.emptyTitle);
23899 e.set(this.parent.valueField, '');
23904 this.fireEvent("load", this, r, options, o);
23905 if(options.callback){
23906 options.callback.call(options.scope || this, r, options, true);
23912 * Loads data from a passed data block. A Reader which understands the format of the data
23913 * must have been configured in the constructor.
23914 * @param {Object} data The data block from which to read the Records. The format of the data expected
23915 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
23916 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
23918 loadData : function(o, append){
23919 var r = this.reader.readRecords(o);
23920 this.loadRecords(r, {add: append}, true);
23924 * using 'cn' the nested child reader read the child array into it's child stores.
23925 * @param {Object} rec The record with a 'children array
23927 loadDataFromChildren : function(rec)
23929 this.loadData(this.reader.toLoadData(rec));
23934 * Gets the number of cached records.
23936 * <em>If using paging, this may not be the total size of the dataset. If the data object
23937 * used by the Reader contains the dataset size, then the getTotalCount() function returns
23938 * the data set size</em>
23940 getCount : function(){
23941 return this.data.length || 0;
23945 * Gets the total number of records in the dataset as returned by the server.
23947 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
23948 * the dataset size</em>
23950 getTotalCount : function(){
23951 return this.totalLength || 0;
23955 * Returns the sort state of the Store as an object with two properties:
23957 field {String} The name of the field by which the Records are sorted
23958 direction {String} The sort order, "ASC" or "DESC"
23961 getSortState : function(){
23962 return this.sortInfo;
23966 applySort : function(){
23967 if(this.sortInfo && !this.remoteSort){
23968 var s = this.sortInfo, f = s.field;
23969 var st = this.fields.get(f).sortType;
23970 var fn = function(r1, r2){
23971 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
23972 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
23974 this.data.sort(s.direction, fn);
23975 if(this.snapshot && this.snapshot != this.data){
23976 this.snapshot.sort(s.direction, fn);
23982 * Sets the default sort column and order to be used by the next load operation.
23983 * @param {String} fieldName The name of the field to sort by.
23984 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
23986 setDefaultSort : function(field, dir){
23987 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
23991 * Sort the Records.
23992 * If remote sorting is used, the sort is performed on the server, and the cache is
23993 * reloaded. If local sorting is used, the cache is sorted internally.
23994 * @param {String} fieldName The name of the field to sort by.
23995 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
23997 sort : function(fieldName, dir){
23998 var f = this.fields.get(fieldName);
24000 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
24002 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
24003 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
24008 this.sortToggle[f.name] = dir;
24009 this.sortInfo = {field: f.name, direction: dir};
24010 if(!this.remoteSort){
24012 this.fireEvent("datachanged", this);
24014 this.load(this.lastOptions);
24019 * Calls the specified function for each of the Records in the cache.
24020 * @param {Function} fn The function to call. The Record is passed as the first parameter.
24021 * Returning <em>false</em> aborts and exits the iteration.
24022 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
24024 each : function(fn, scope){
24025 this.data.each(fn, scope);
24029 * Gets all records modified since the last commit. Modified records are persisted across load operations
24030 * (e.g., during paging).
24031 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
24033 getModifiedRecords : function(){
24034 return this.modified;
24038 createFilterFn : function(property, value, anyMatch){
24039 if(!value.exec){ // not a regex
24040 value = String(value);
24041 if(value.length == 0){
24044 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
24046 return function(r){
24047 return value.test(r.data[property]);
24052 * Sums the value of <i>property</i> for each record between start and end and returns the result.
24053 * @param {String} property A field on your records
24054 * @param {Number} start The record index to start at (defaults to 0)
24055 * @param {Number} end The last record index to include (defaults to length - 1)
24056 * @return {Number} The sum
24058 sum : function(property, start, end){
24059 var rs = this.data.items, v = 0;
24060 start = start || 0;
24061 end = (end || end === 0) ? end : rs.length-1;
24063 for(var i = start; i <= end; i++){
24064 v += (rs[i].data[property] || 0);
24070 * Filter the records by a specified property.
24071 * @param {String} field A field on your records
24072 * @param {String/RegExp} value Either a string that the field
24073 * should start with or a RegExp to test against the field
24074 * @param {Boolean} anyMatch True to match any part not just the beginning
24076 filter : function(property, value, anyMatch){
24077 var fn = this.createFilterFn(property, value, anyMatch);
24078 return fn ? this.filterBy(fn) : this.clearFilter();
24082 * Filter by a function. The specified function will be called with each
24083 * record in this data source. If the function returns true the record is included,
24084 * otherwise it is filtered.
24085 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
24086 * @param {Object} scope (optional) The scope of the function (defaults to this)
24088 filterBy : function(fn, scope){
24089 this.snapshot = this.snapshot || this.data;
24090 this.data = this.queryBy(fn, scope||this);
24091 this.fireEvent("datachanged", this);
24095 * Query the records by a specified property.
24096 * @param {String} field A field on your records
24097 * @param {String/RegExp} value Either a string that the field
24098 * should start with or a RegExp to test against the field
24099 * @param {Boolean} anyMatch True to match any part not just the beginning
24100 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
24102 query : function(property, value, anyMatch){
24103 var fn = this.createFilterFn(property, value, anyMatch);
24104 return fn ? this.queryBy(fn) : this.data.clone();
24108 * Query by a function. The specified function will be called with each
24109 * record in this data source. If the function returns true the record is included
24111 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
24112 * @param {Object} scope (optional) The scope of the function (defaults to this)
24113 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
24115 queryBy : function(fn, scope){
24116 var data = this.snapshot || this.data;
24117 return data.filterBy(fn, scope||this);
24121 * Collects unique values for a particular dataIndex from this store.
24122 * @param {String} dataIndex The property to collect
24123 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
24124 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
24125 * @return {Array} An array of the unique values
24127 collect : function(dataIndex, allowNull, bypassFilter){
24128 var d = (bypassFilter === true && this.snapshot) ?
24129 this.snapshot.items : this.data.items;
24130 var v, sv, r = [], l = {};
24131 for(var i = 0, len = d.length; i < len; i++){
24132 v = d[i].data[dataIndex];
24134 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
24143 * Revert to a view of the Record cache with no filtering applied.
24144 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
24146 clearFilter : function(suppressEvent){
24147 if(this.snapshot && this.snapshot != this.data){
24148 this.data = this.snapshot;
24149 delete this.snapshot;
24150 if(suppressEvent !== true){
24151 this.fireEvent("datachanged", this);
24157 afterEdit : function(record){
24158 if(this.modified.indexOf(record) == -1){
24159 this.modified.push(record);
24161 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
24165 afterReject : function(record){
24166 this.modified.remove(record);
24167 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
24171 afterCommit : function(record){
24172 this.modified.remove(record);
24173 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
24177 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
24178 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
24180 commitChanges : function(){
24181 var m = this.modified.slice(0);
24182 this.modified = [];
24183 for(var i = 0, len = m.length; i < len; i++){
24189 * Cancel outstanding changes on all changed records.
24191 rejectChanges : function(){
24192 var m = this.modified.slice(0);
24193 this.modified = [];
24194 for(var i = 0, len = m.length; i < len; i++){
24199 onMetaChange : function(meta, rtype, o){
24200 this.recordType = rtype;
24201 this.fields = rtype.prototype.fields;
24202 delete this.snapshot;
24203 this.sortInfo = meta.sortInfo || this.sortInfo;
24204 this.modified = [];
24205 this.fireEvent('metachange', this, this.reader.meta);
24208 moveIndex : function(data, type)
24210 var index = this.indexOf(data);
24212 var newIndex = index + type;
24216 this.insert(newIndex, data);
24221 * Ext JS Library 1.1.1
24222 * Copyright(c) 2006-2007, Ext JS, LLC.
24224 * Originally Released Under LGPL - original licence link has changed is not relivant.
24227 * <script type="text/javascript">
24231 * @class Roo.data.SimpleStore
24232 * @extends Roo.data.Store
24233 * Small helper class to make creating Stores from Array data easier.
24234 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
24235 * @cfg {Array} fields An array of field definition objects, or field name strings.
24236 * @cfg {Object} an existing reader (eg. copied from another store)
24237 * @cfg {Array} data The multi-dimensional array of data
24239 * @param {Object} config
24241 Roo.data.SimpleStore = function(config)
24243 Roo.data.SimpleStore.superclass.constructor.call(this, {
24245 reader: typeof(config.reader) != 'undefined' ? config.reader : new Roo.data.ArrayReader({
24248 Roo.data.Record.create(config.fields)
24250 proxy : new Roo.data.MemoryProxy(config.data)
24254 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
24256 * Ext JS Library 1.1.1
24257 * Copyright(c) 2006-2007, Ext JS, LLC.
24259 * Originally Released Under LGPL - original licence link has changed is not relivant.
24262 * <script type="text/javascript">
24267 * @extends Roo.data.Store
24268 * @class Roo.data.JsonStore
24269 * Small helper class to make creating Stores for JSON data easier. <br/>
24271 var store = new Roo.data.JsonStore({
24272 url: 'get-images.php',
24274 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
24277 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
24278 * JsonReader and HttpProxy (unless inline data is provided).</b>
24279 * @cfg {Array} fields An array of field definition objects, or field name strings.
24281 * @param {Object} config
24283 Roo.data.JsonStore = function(c){
24284 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
24285 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
24286 reader: new Roo.data.JsonReader(c, c.fields)
24289 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
24291 * Ext JS Library 1.1.1
24292 * Copyright(c) 2006-2007, Ext JS, LLC.
24294 * Originally Released Under LGPL - original licence link has changed is not relivant.
24297 * <script type="text/javascript">
24301 Roo.data.Field = function(config){
24302 if(typeof config == "string"){
24303 config = {name: config};
24305 Roo.apply(this, config);
24308 this.type = "auto";
24311 var st = Roo.data.SortTypes;
24312 // named sortTypes are supported, here we look them up
24313 if(typeof this.sortType == "string"){
24314 this.sortType = st[this.sortType];
24317 // set default sortType for strings and dates
24318 if(!this.sortType){
24321 this.sortType = st.asUCString;
24324 this.sortType = st.asDate;
24327 this.sortType = st.none;
24332 var stripRe = /[\$,%]/g;
24334 // prebuilt conversion function for this field, instead of
24335 // switching every time we're reading a value
24337 var cv, dateFormat = this.dateFormat;
24342 cv = function(v){ return v; };
24345 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
24349 return v !== undefined && v !== null && v !== '' ?
24350 parseInt(String(v).replace(stripRe, ""), 10) : '';
24355 return v !== undefined && v !== null && v !== '' ?
24356 parseFloat(String(v).replace(stripRe, ""), 10) : '';
24361 cv = function(v){ return v === true || v === "true" || v == 1; };
24368 if(v instanceof Date){
24372 if(dateFormat == "timestamp"){
24373 return new Date(v*1000);
24375 return Date.parseDate(v, dateFormat);
24377 var parsed = Date.parse(v);
24378 return parsed ? new Date(parsed) : null;
24387 Roo.data.Field.prototype = {
24395 * Ext JS Library 1.1.1
24396 * Copyright(c) 2006-2007, Ext JS, LLC.
24398 * Originally Released Under LGPL - original licence link has changed is not relivant.
24401 * <script type="text/javascript">
24404 // Base class for reading structured data from a data source. This class is intended to be
24405 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
24408 * @class Roo.data.DataReader
24409 * Base class for reading structured data from a data source. This class is intended to be
24410 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
24413 Roo.data.DataReader = function(meta, recordType){
24417 this.recordType = recordType instanceof Array ?
24418 Roo.data.Record.create(recordType) : recordType;
24421 Roo.data.DataReader.prototype = {
24424 readerType : 'Data',
24426 * Create an empty record
24427 * @param {Object} data (optional) - overlay some values
24428 * @return {Roo.data.Record} record created.
24430 newRow : function(d) {
24432 this.recordType.prototype.fields.each(function(c) {
24434 case 'int' : da[c.name] = 0; break;
24435 case 'date' : da[c.name] = new Date(); break;
24436 case 'float' : da[c.name] = 0.0; break;
24437 case 'boolean' : da[c.name] = false; break;
24438 default : da[c.name] = ""; break;
24442 return new this.recordType(Roo.apply(da, d));
24448 * Ext JS Library 1.1.1
24449 * Copyright(c) 2006-2007, Ext JS, LLC.
24451 * Originally Released Under LGPL - original licence link has changed is not relivant.
24454 * <script type="text/javascript">
24458 * @class Roo.data.DataProxy
24459 * @extends Roo.data.Observable
24460 * This class is an abstract base class for implementations which provide retrieval of
24461 * unformatted data objects.<br>
24463 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
24464 * (of the appropriate type which knows how to parse the data object) to provide a block of
24465 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
24467 * Custom implementations must implement the load method as described in
24468 * {@link Roo.data.HttpProxy#load}.
24470 Roo.data.DataProxy = function(){
24473 * @event beforeload
24474 * Fires before a network request is made to retrieve a data object.
24475 * @param {Object} This DataProxy object.
24476 * @param {Object} params The params parameter to the load function.
24481 * Fires before the load method's callback is called.
24482 * @param {Object} This DataProxy object.
24483 * @param {Object} o The data object.
24484 * @param {Object} arg The callback argument object passed to the load function.
24488 * @event loadexception
24489 * Fires if an Exception occurs during data retrieval.
24490 * @param {Object} This DataProxy object.
24491 * @param {Object} o The data object.
24492 * @param {Object} arg The callback argument object passed to the load function.
24493 * @param {Object} e The Exception.
24495 loadexception : true
24497 Roo.data.DataProxy.superclass.constructor.call(this);
24500 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
24503 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
24507 * Ext JS Library 1.1.1
24508 * Copyright(c) 2006-2007, Ext JS, LLC.
24510 * Originally Released Under LGPL - original licence link has changed is not relivant.
24513 * <script type="text/javascript">
24516 * @class Roo.data.MemoryProxy
24517 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
24518 * to the Reader when its load method is called.
24520 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
24522 Roo.data.MemoryProxy = function(data){
24526 Roo.data.MemoryProxy.superclass.constructor.call(this);
24530 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
24533 * Load data from the requested source (in this case an in-memory
24534 * data object passed to the constructor), read the data object into
24535 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
24536 * process that block using the passed callback.
24537 * @param {Object} params This parameter is not used by the MemoryProxy class.
24538 * @param {Roo.data.DataReader} reader The Reader object which converts the data
24539 * object into a block of Roo.data.Records.
24540 * @param {Function} callback The function into which to pass the block of Roo.data.records.
24541 * The function must be passed <ul>
24542 * <li>The Record block object</li>
24543 * <li>The "arg" argument from the load function</li>
24544 * <li>A boolean success indicator</li>
24546 * @param {Object} scope The scope in which to call the callback
24547 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
24549 load : function(params, reader, callback, scope, arg){
24550 params = params || {};
24553 result = reader.readRecords(params.data ? params.data :this.data);
24555 this.fireEvent("loadexception", this, arg, null, e);
24556 callback.call(scope, null, arg, false);
24559 callback.call(scope, result, arg, true);
24563 update : function(params, records){
24568 * Ext JS Library 1.1.1
24569 * Copyright(c) 2006-2007, Ext JS, LLC.
24571 * Originally Released Under LGPL - original licence link has changed is not relivant.
24574 * <script type="text/javascript">
24577 * @class Roo.data.HttpProxy
24578 * @extends Roo.data.DataProxy
24579 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
24580 * configured to reference a certain URL.<br><br>
24582 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
24583 * from which the running page was served.<br><br>
24585 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
24587 * Be aware that to enable the browser to parse an XML document, the server must set
24588 * the Content-Type header in the HTTP response to "text/xml".
24590 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
24591 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
24592 * will be used to make the request.
24594 Roo.data.HttpProxy = function(conn){
24595 Roo.data.HttpProxy.superclass.constructor.call(this);
24596 // is conn a conn config or a real conn?
24598 this.useAjax = !conn || !conn.events;
24602 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
24603 // thse are take from connection...
24606 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
24609 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
24610 * extra parameters to each request made by this object. (defaults to undefined)
24613 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
24614 * to each request made by this object. (defaults to undefined)
24617 * @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)
24620 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
24623 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
24629 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
24633 * Return the {@link Roo.data.Connection} object being used by this Proxy.
24634 * @return {Connection} The Connection object. This object may be used to subscribe to events on
24635 * a finer-grained basis than the DataProxy events.
24637 getConnection : function(){
24638 return this.useAjax ? Roo.Ajax : this.conn;
24642 * Load data from the configured {@link Roo.data.Connection}, read the data object into
24643 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
24644 * process that block using the passed callback.
24645 * @param {Object} params An object containing properties which are to be used as HTTP parameters
24646 * for the request to the remote server.
24647 * @param {Roo.data.DataReader} reader The Reader object which converts the data
24648 * object into a block of Roo.data.Records.
24649 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
24650 * The function must be passed <ul>
24651 * <li>The Record block object</li>
24652 * <li>The "arg" argument from the load function</li>
24653 * <li>A boolean success indicator</li>
24655 * @param {Object} scope The scope in which to call the callback
24656 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
24658 load : function(params, reader, callback, scope, arg){
24659 if(this.fireEvent("beforeload", this, params) !== false){
24661 params : params || {},
24663 callback : callback,
24668 callback : this.loadResponse,
24672 Roo.applyIf(o, this.conn);
24673 if(this.activeRequest){
24674 Roo.Ajax.abort(this.activeRequest);
24676 this.activeRequest = Roo.Ajax.request(o);
24678 this.conn.request(o);
24681 callback.call(scope||this, null, arg, false);
24686 loadResponse : function(o, success, response){
24687 delete this.activeRequest;
24689 this.fireEvent("loadexception", this, o, response);
24690 o.request.callback.call(o.request.scope, null, o.request.arg, false);
24695 result = o.reader.read(response);
24697 this.fireEvent("loadexception", this, o, response, e);
24698 o.request.callback.call(o.request.scope, null, o.request.arg, false);
24702 this.fireEvent("load", this, o, o.request.arg);
24703 o.request.callback.call(o.request.scope, result, o.request.arg, true);
24707 update : function(dataSet){
24712 updateResponse : function(dataSet){
24717 * Ext JS Library 1.1.1
24718 * Copyright(c) 2006-2007, Ext JS, LLC.
24720 * Originally Released Under LGPL - original licence link has changed is not relivant.
24723 * <script type="text/javascript">
24727 * @class Roo.data.ScriptTagProxy
24728 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
24729 * other than the originating domain of the running page.<br><br>
24731 * <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
24732 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
24734 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
24735 * source code that is used as the source inside a <script> tag.<br><br>
24737 * In order for the browser to process the returned data, the server must wrap the data object
24738 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
24739 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
24740 * depending on whether the callback name was passed:
24743 boolean scriptTag = false;
24744 String cb = request.getParameter("callback");
24747 response.setContentType("text/javascript");
24749 response.setContentType("application/x-json");
24751 Writer out = response.getWriter();
24753 out.write(cb + "(");
24755 out.print(dataBlock.toJsonString());
24762 * @param {Object} config A configuration object.
24764 Roo.data.ScriptTagProxy = function(config){
24765 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
24766 Roo.apply(this, config);
24767 this.head = document.getElementsByTagName("head")[0];
24770 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
24772 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
24774 * @cfg {String} url The URL from which to request the data object.
24777 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
24781 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
24782 * the server the name of the callback function set up by the load call to process the returned data object.
24783 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
24784 * javascript output which calls this named function passing the data object as its only parameter.
24786 callbackParam : "callback",
24788 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
24789 * name to the request.
24794 * Load data from the configured URL, read the data object into
24795 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
24796 * process that block using the passed callback.
24797 * @param {Object} params An object containing properties which are to be used as HTTP parameters
24798 * for the request to the remote server.
24799 * @param {Roo.data.DataReader} reader The Reader object which converts the data
24800 * object into a block of Roo.data.Records.
24801 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
24802 * The function must be passed <ul>
24803 * <li>The Record block object</li>
24804 * <li>The "arg" argument from the load function</li>
24805 * <li>A boolean success indicator</li>
24807 * @param {Object} scope The scope in which to call the callback
24808 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
24810 load : function(params, reader, callback, scope, arg){
24811 if(this.fireEvent("beforeload", this, params) !== false){
24813 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
24815 var url = this.url;
24816 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
24818 url += "&_dc=" + (new Date().getTime());
24820 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
24823 cb : "stcCallback"+transId,
24824 scriptId : "stcScript"+transId,
24828 callback : callback,
24834 window[trans.cb] = function(o){
24835 conn.handleResponse(o, trans);
24838 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
24840 if(this.autoAbort !== false){
24844 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
24846 var script = document.createElement("script");
24847 script.setAttribute("src", url);
24848 script.setAttribute("type", "text/javascript");
24849 script.setAttribute("id", trans.scriptId);
24850 this.head.appendChild(script);
24852 this.trans = trans;
24854 callback.call(scope||this, null, arg, false);
24859 isLoading : function(){
24860 return this.trans ? true : false;
24864 * Abort the current server request.
24866 abort : function(){
24867 if(this.isLoading()){
24868 this.destroyTrans(this.trans);
24873 destroyTrans : function(trans, isLoaded){
24874 this.head.removeChild(document.getElementById(trans.scriptId));
24875 clearTimeout(trans.timeoutId);
24877 window[trans.cb] = undefined;
24879 delete window[trans.cb];
24882 // if hasn't been loaded, wait for load to remove it to prevent script error
24883 window[trans.cb] = function(){
24884 window[trans.cb] = undefined;
24886 delete window[trans.cb];
24893 handleResponse : function(o, trans){
24894 this.trans = false;
24895 this.destroyTrans(trans, true);
24898 result = trans.reader.readRecords(o);
24900 this.fireEvent("loadexception", this, o, trans.arg, e);
24901 trans.callback.call(trans.scope||window, null, trans.arg, false);
24904 this.fireEvent("load", this, o, trans.arg);
24905 trans.callback.call(trans.scope||window, result, trans.arg, true);
24909 handleFailure : function(trans){
24910 this.trans = false;
24911 this.destroyTrans(trans, false);
24912 this.fireEvent("loadexception", this, null, trans.arg);
24913 trans.callback.call(trans.scope||window, null, trans.arg, false);
24917 * Ext JS Library 1.1.1
24918 * Copyright(c) 2006-2007, Ext JS, LLC.
24920 * Originally Released Under LGPL - original licence link has changed is not relivant.
24923 * <script type="text/javascript">
24927 * @class Roo.data.JsonReader
24928 * @extends Roo.data.DataReader
24929 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
24930 * based on mappings in a provided Roo.data.Record constructor.
24932 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
24933 * in the reply previously.
24938 var RecordDef = Roo.data.Record.create([
24939 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
24940 {name: 'occupation'} // This field will use "occupation" as the mapping.
24942 var myReader = new Roo.data.JsonReader({
24943 totalProperty: "results", // The property which contains the total dataset size (optional)
24944 root: "rows", // The property which contains an Array of row objects
24945 id: "id" // The property within each row object that provides an ID for the record (optional)
24949 * This would consume a JSON file like this:
24951 { 'results': 2, 'rows': [
24952 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
24953 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
24956 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
24957 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
24958 * paged from the remote server.
24959 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
24960 * @cfg {String} root name of the property which contains the Array of row objects.
24961 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
24962 * @cfg {Array} fields Array of field definition objects
24964 * Create a new JsonReader
24965 * @param {Object} meta Metadata configuration options
24966 * @param {Object} recordType Either an Array of field definition objects,
24967 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
24969 Roo.data.JsonReader = function(meta, recordType){
24972 // set some defaults:
24973 Roo.applyIf(meta, {
24974 totalProperty: 'total',
24975 successProperty : 'success',
24980 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
24982 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
24984 readerType : 'Json',
24987 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
24988 * Used by Store query builder to append _requestMeta to params.
24991 metaFromRemote : false,
24993 * This method is only used by a DataProxy which has retrieved data from a remote server.
24994 * @param {Object} response The XHR object which contains the JSON data in its responseText.
24995 * @return {Object} data A data block which is used by an Roo.data.Store object as
24996 * a cache of Roo.data.Records.
24998 read : function(response){
24999 var json = response.responseText;
25001 var o = /* eval:var:o */ eval("("+json+")");
25003 throw {message: "JsonReader.read: Json object not found"};
25009 this.metaFromRemote = true;
25010 this.meta = o.metaData;
25011 this.recordType = Roo.data.Record.create(o.metaData.fields);
25012 this.onMetaChange(this.meta, this.recordType, o);
25014 return this.readRecords(o);
25017 // private function a store will implement
25018 onMetaChange : function(meta, recordType, o){
25025 simpleAccess: function(obj, subsc) {
25032 getJsonAccessor: function(){
25034 return function(expr) {
25036 return(re.test(expr))
25037 ? new Function("obj", "return obj." + expr)
25042 return Roo.emptyFn;
25047 * Create a data block containing Roo.data.Records from an XML document.
25048 * @param {Object} o An object which contains an Array of row objects in the property specified
25049 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
25050 * which contains the total size of the dataset.
25051 * @return {Object} data A data block which is used by an Roo.data.Store object as
25052 * a cache of Roo.data.Records.
25054 readRecords : function(o){
25056 * After any data loads, the raw JSON data is available for further custom processing.
25060 var s = this.meta, Record = this.recordType,
25061 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
25063 // Generate extraction functions for the totalProperty, the root, the id, and for each field
25065 if(s.totalProperty) {
25066 this.getTotal = this.getJsonAccessor(s.totalProperty);
25068 if(s.successProperty) {
25069 this.getSuccess = this.getJsonAccessor(s.successProperty);
25071 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
25073 var g = this.getJsonAccessor(s.id);
25074 this.getId = function(rec) {
25076 return (r === undefined || r === "") ? null : r;
25079 this.getId = function(){return null;};
25082 for(var jj = 0; jj < fl; jj++){
25084 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
25085 this.ef[jj] = this.getJsonAccessor(map);
25089 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
25090 if(s.totalProperty){
25091 var vt = parseInt(this.getTotal(o), 10);
25096 if(s.successProperty){
25097 var vs = this.getSuccess(o);
25098 if(vs === false || vs === 'false'){
25103 for(var i = 0; i < c; i++){
25106 var id = this.getId(n);
25107 for(var j = 0; j < fl; j++){
25109 var v = this.ef[j](n);
25111 Roo.log('missing convert for ' + f.name);
25115 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
25117 var record = new Record(values, id);
25119 records[i] = record;
25125 totalRecords : totalRecords
25128 // used when loading children.. @see loadDataFromChildren
25129 toLoadData: function(rec)
25131 // expect rec just to be an array.. eg [a,b,c, [...] << cn ]
25132 var data = typeof(rec.data.cn) == 'undefined' ? [] : rec.data.cn;
25133 return { data : data, total : data.length };
25138 * Ext JS Library 1.1.1
25139 * Copyright(c) 2006-2007, Ext JS, LLC.
25141 * Originally Released Under LGPL - original licence link has changed is not relivant.
25144 * <script type="text/javascript">
25148 * @class Roo.data.XmlReader
25149 * @extends Roo.data.DataReader
25150 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
25151 * based on mappings in a provided Roo.data.Record constructor.<br><br>
25153 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
25154 * header in the HTTP response must be set to "text/xml".</em>
25158 var RecordDef = Roo.data.Record.create([
25159 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
25160 {name: 'occupation'} // This field will use "occupation" as the mapping.
25162 var myReader = new Roo.data.XmlReader({
25163 totalRecords: "results", // The element which contains the total dataset size (optional)
25164 record: "row", // The repeated element which contains row information
25165 id: "id" // The element within the row that provides an ID for the record (optional)
25169 * This would consume an XML file like this:
25173 <results>2</results>
25176 <name>Bill</name>
25177 <occupation>Gardener</occupation>
25181 <name>Ben</name>
25182 <occupation>Horticulturalist</occupation>
25186 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
25187 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
25188 * paged from the remote server.
25189 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
25190 * @cfg {String} success The DomQuery path to the success attribute used by forms.
25191 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
25192 * a record identifier value.
25194 * Create a new XmlReader
25195 * @param {Object} meta Metadata configuration options
25196 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
25197 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
25198 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
25200 Roo.data.XmlReader = function(meta, recordType){
25202 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
25204 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
25206 readerType : 'Xml',
25209 * This method is only used by a DataProxy which has retrieved data from a remote server.
25210 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
25211 * to contain a method called 'responseXML' that returns an XML document object.
25212 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
25213 * a cache of Roo.data.Records.
25215 read : function(response){
25216 var doc = response.responseXML;
25218 throw {message: "XmlReader.read: XML Document not available"};
25220 return this.readRecords(doc);
25224 * Create a data block containing Roo.data.Records from an XML document.
25225 * @param {Object} doc A parsed XML document.
25226 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
25227 * a cache of Roo.data.Records.
25229 readRecords : function(doc){
25231 * After any data loads/reads, the raw XML Document is available for further custom processing.
25232 * @type XMLDocument
25234 this.xmlData = doc;
25235 var root = doc.documentElement || doc;
25236 var q = Roo.DomQuery;
25237 var recordType = this.recordType, fields = recordType.prototype.fields;
25238 var sid = this.meta.id;
25239 var totalRecords = 0, success = true;
25240 if(this.meta.totalRecords){
25241 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
25244 if(this.meta.success){
25245 var sv = q.selectValue(this.meta.success, root, true);
25246 success = sv !== false && sv !== 'false';
25249 var ns = q.select(this.meta.record, root);
25250 for(var i = 0, len = ns.length; i < len; i++) {
25253 var id = sid ? q.selectValue(sid, n) : undefined;
25254 for(var j = 0, jlen = fields.length; j < jlen; j++){
25255 var f = fields.items[j];
25256 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
25258 values[f.name] = v;
25260 var record = new recordType(values, id);
25262 records[records.length] = record;
25268 totalRecords : totalRecords || records.length
25273 * Ext JS Library 1.1.1
25274 * Copyright(c) 2006-2007, Ext JS, LLC.
25276 * Originally Released Under LGPL - original licence link has changed is not relivant.
25279 * <script type="text/javascript">
25283 * @class Roo.data.ArrayReader
25284 * @extends Roo.data.DataReader
25285 * Data reader class to create an Array of Roo.data.Record objects from an Array.
25286 * Each element of that Array represents a row of data fields. The
25287 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
25288 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
25292 var RecordDef = Roo.data.Record.create([
25293 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
25294 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
25296 var myReader = new Roo.data.ArrayReader({
25297 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
25301 * This would consume an Array like this:
25303 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
25307 * Create a new JsonReader
25308 * @param {Object} meta Metadata configuration options.
25309 * @param {Object|Array} recordType Either an Array of field definition objects
25311 * @cfg {Array} fields Array of field definition objects
25312 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
25313 * as specified to {@link Roo.data.Record#create},
25314 * or an {@link Roo.data.Record} object
25317 * created using {@link Roo.data.Record#create}.
25319 Roo.data.ArrayReader = function(meta, recordType)
25321 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType||meta.fields);
25324 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
25327 * Create a data block containing Roo.data.Records from an XML document.
25328 * @param {Object} o An Array of row objects which represents the dataset.
25329 * @return {Object} A data block which is used by an {@link Roo.data.Store} object as
25330 * a cache of Roo.data.Records.
25332 readRecords : function(o)
25334 var sid = this.meta ? this.meta.id : null;
25335 var recordType = this.recordType, fields = recordType.prototype.fields;
25338 for(var i = 0; i < root.length; i++){
25341 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
25342 for(var j = 0, jlen = fields.length; j < jlen; j++){
25343 var f = fields.items[j];
25344 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
25345 var v = n[k] !== undefined ? n[k] : f.defaultValue;
25347 values[f.name] = v;
25349 var record = new recordType(values, id);
25351 records[records.length] = record;
25355 totalRecords : records.length
25358 // used when loading children.. @see loadDataFromChildren
25359 toLoadData: function(rec)
25361 // expect rec just to be an array.. eg [a,b,c, [...] << cn ]
25362 return typeof(rec.data.cn) == 'undefined' ? [] : rec.data.cn;
25369 * Ext JS Library 1.1.1
25370 * Copyright(c) 2006-2007, Ext JS, LLC.
25372 * Originally Released Under LGPL - original licence link has changed is not relivant.
25375 * <script type="text/javascript">
25380 * @class Roo.data.Tree
25381 * @extends Roo.util.Observable
25382 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
25383 * in the tree have most standard DOM functionality.
25385 * @param {Node} root (optional) The root node
25387 Roo.data.Tree = function(root){
25388 this.nodeHash = {};
25390 * The root node for this tree
25395 this.setRootNode(root);
25400 * Fires when a new child node is appended to a node in this tree.
25401 * @param {Tree} tree The owner tree
25402 * @param {Node} parent The parent node
25403 * @param {Node} node The newly appended node
25404 * @param {Number} index The index of the newly appended node
25409 * Fires when a child node is removed from a node in this tree.
25410 * @param {Tree} tree The owner tree
25411 * @param {Node} parent The parent node
25412 * @param {Node} node The child node removed
25417 * Fires when a node is moved to a new location in the tree
25418 * @param {Tree} tree The owner tree
25419 * @param {Node} node The node moved
25420 * @param {Node} oldParent The old parent of this node
25421 * @param {Node} newParent The new parent of this node
25422 * @param {Number} index The index it was moved to
25427 * Fires when a new child node is inserted in a node in this tree.
25428 * @param {Tree} tree The owner tree
25429 * @param {Node} parent The parent node
25430 * @param {Node} node The child node inserted
25431 * @param {Node} refNode The child node the node was inserted before
25435 * @event beforeappend
25436 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
25437 * @param {Tree} tree The owner tree
25438 * @param {Node} parent The parent node
25439 * @param {Node} node The child node to be appended
25441 "beforeappend" : true,
25443 * @event beforeremove
25444 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
25445 * @param {Tree} tree The owner tree
25446 * @param {Node} parent The parent node
25447 * @param {Node} node The child node to be removed
25449 "beforeremove" : true,
25451 * @event beforemove
25452 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
25453 * @param {Tree} tree The owner tree
25454 * @param {Node} node The node being moved
25455 * @param {Node} oldParent The parent of the node
25456 * @param {Node} newParent The new parent the node is moving to
25457 * @param {Number} index The index it is being moved to
25459 "beforemove" : true,
25461 * @event beforeinsert
25462 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
25463 * @param {Tree} tree The owner tree
25464 * @param {Node} parent The parent node
25465 * @param {Node} node The child node to be inserted
25466 * @param {Node} refNode The child node the node is being inserted before
25468 "beforeinsert" : true
25471 Roo.data.Tree.superclass.constructor.call(this);
25474 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
25475 pathSeparator: "/",
25477 proxyNodeEvent : function(){
25478 return this.fireEvent.apply(this, arguments);
25482 * Returns the root node for this tree.
25485 getRootNode : function(){
25490 * Sets the root node for this tree.
25491 * @param {Node} node
25494 setRootNode : function(node){
25496 node.ownerTree = this;
25497 node.isRoot = true;
25498 this.registerNode(node);
25503 * Gets a node in this tree by its id.
25504 * @param {String} id
25507 getNodeById : function(id){
25508 return this.nodeHash[id];
25511 registerNode : function(node){
25512 this.nodeHash[node.id] = node;
25515 unregisterNode : function(node){
25516 delete this.nodeHash[node.id];
25519 toString : function(){
25520 return "[Tree"+(this.id?" "+this.id:"")+"]";
25525 * @class Roo.data.Node
25526 * @extends Roo.util.Observable
25527 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
25528 * @cfg {String} id The id for this node. If one is not specified, one is generated.
25530 * @param {Object} attributes The attributes/config for the node
25532 Roo.data.Node = function(attributes){
25534 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
25537 this.attributes = attributes || {};
25538 this.leaf = this.attributes.leaf;
25540 * The node id. @type String
25542 this.id = this.attributes.id;
25544 this.id = Roo.id(null, "ynode-");
25545 this.attributes.id = this.id;
25550 * All child nodes of this node. @type Array
25552 this.childNodes = [];
25553 if(!this.childNodes.indexOf){ // indexOf is a must
25554 this.childNodes.indexOf = function(o){
25555 for(var i = 0, len = this.length; i < len; i++){
25564 * The parent node for this node. @type Node
25566 this.parentNode = null;
25568 * The first direct child node of this node, or null if this node has no child nodes. @type Node
25570 this.firstChild = null;
25572 * The last direct child node of this node, or null if this node has no child nodes. @type Node
25574 this.lastChild = null;
25576 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
25578 this.previousSibling = null;
25580 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
25582 this.nextSibling = null;
25587 * Fires when a new child node is appended
25588 * @param {Tree} tree The owner tree
25589 * @param {Node} this This node
25590 * @param {Node} node The newly appended node
25591 * @param {Number} index The index of the newly appended node
25596 * Fires when a child node is removed
25597 * @param {Tree} tree The owner tree
25598 * @param {Node} this This node
25599 * @param {Node} node The removed node
25604 * Fires when this node is moved to a new location in the tree
25605 * @param {Tree} tree The owner tree
25606 * @param {Node} this This node
25607 * @param {Node} oldParent The old parent of this node
25608 * @param {Node} newParent The new parent of this node
25609 * @param {Number} index The index it was moved to
25614 * Fires when a new child node is inserted.
25615 * @param {Tree} tree The owner tree
25616 * @param {Node} this This node
25617 * @param {Node} node The child node inserted
25618 * @param {Node} refNode The child node the node was inserted before
25622 * @event beforeappend
25623 * Fires before a new child is appended, return false to cancel the append.
25624 * @param {Tree} tree The owner tree
25625 * @param {Node} this This node
25626 * @param {Node} node The child node to be appended
25628 "beforeappend" : true,
25630 * @event beforeremove
25631 * Fires before a child is removed, return false to cancel the remove.
25632 * @param {Tree} tree The owner tree
25633 * @param {Node} this This node
25634 * @param {Node} node The child node to be removed
25636 "beforeremove" : true,
25638 * @event beforemove
25639 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
25640 * @param {Tree} tree The owner tree
25641 * @param {Node} this This node
25642 * @param {Node} oldParent The parent of this node
25643 * @param {Node} newParent The new parent this node is moving to
25644 * @param {Number} index The index it is being moved to
25646 "beforemove" : true,
25648 * @event beforeinsert
25649 * Fires before a new child is inserted, return false to cancel the insert.
25650 * @param {Tree} tree The owner tree
25651 * @param {Node} this This node
25652 * @param {Node} node The child node to be inserted
25653 * @param {Node} refNode The child node the node is being inserted before
25655 "beforeinsert" : true
25657 this.listeners = this.attributes.listeners;
25658 Roo.data.Node.superclass.constructor.call(this);
25661 Roo.extend(Roo.data.Node, Roo.util.Observable, {
25662 fireEvent : function(evtName){
25663 // first do standard event for this node
25664 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
25667 // then bubble it up to the tree if the event wasn't cancelled
25668 var ot = this.getOwnerTree();
25670 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
25678 * Returns true if this node is a leaf
25679 * @return {Boolean}
25681 isLeaf : function(){
25682 return this.leaf === true;
25686 setFirstChild : function(node){
25687 this.firstChild = node;
25691 setLastChild : function(node){
25692 this.lastChild = node;
25697 * Returns true if this node is the last child of its parent
25698 * @return {Boolean}
25700 isLast : function(){
25701 return (!this.parentNode ? true : this.parentNode.lastChild == this);
25705 * Returns true if this node is the first child of its parent
25706 * @return {Boolean}
25708 isFirst : function(){
25709 return (!this.parentNode ? true : this.parentNode.firstChild == this);
25712 hasChildNodes : function(){
25713 return !this.isLeaf() && this.childNodes.length > 0;
25717 * Insert node(s) as the last child node of this node.
25718 * @param {Node/Array} node The node or Array of nodes to append
25719 * @return {Node} The appended node if single append, or null if an array was passed
25721 appendChild : function(node){
25723 if(node instanceof Array){
25725 }else if(arguments.length > 1){
25729 // if passed an array or multiple args do them one by one
25731 for(var i = 0, len = multi.length; i < len; i++) {
25732 this.appendChild(multi[i]);
25735 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
25738 var index = this.childNodes.length;
25739 var oldParent = node.parentNode;
25740 // it's a move, make sure we move it cleanly
25742 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
25745 oldParent.removeChild(node);
25748 index = this.childNodes.length;
25750 this.setFirstChild(node);
25752 this.childNodes.push(node);
25753 node.parentNode = this;
25754 var ps = this.childNodes[index-1];
25756 node.previousSibling = ps;
25757 ps.nextSibling = node;
25759 node.previousSibling = null;
25761 node.nextSibling = null;
25762 this.setLastChild(node);
25763 node.setOwnerTree(this.getOwnerTree());
25764 this.fireEvent("append", this.ownerTree, this, node, index);
25765 if(this.ownerTree) {
25766 this.ownerTree.fireEvent("appendnode", this, node, index);
25769 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
25776 * Removes a child node from this node.
25777 * @param {Node} node The node to remove
25778 * @return {Node} The removed node
25780 removeChild : function(node){
25781 var index = this.childNodes.indexOf(node);
25785 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
25789 // remove it from childNodes collection
25790 this.childNodes.splice(index, 1);
25793 if(node.previousSibling){
25794 node.previousSibling.nextSibling = node.nextSibling;
25796 if(node.nextSibling){
25797 node.nextSibling.previousSibling = node.previousSibling;
25800 // update child refs
25801 if(this.firstChild == node){
25802 this.setFirstChild(node.nextSibling);
25804 if(this.lastChild == node){
25805 this.setLastChild(node.previousSibling);
25808 node.setOwnerTree(null);
25809 // clear any references from the node
25810 node.parentNode = null;
25811 node.previousSibling = null;
25812 node.nextSibling = null;
25813 this.fireEvent("remove", this.ownerTree, this, node);
25818 * Inserts the first node before the second node in this nodes childNodes collection.
25819 * @param {Node} node The node to insert
25820 * @param {Node} refNode The node to insert before (if null the node is appended)
25821 * @return {Node} The inserted node
25823 insertBefore : function(node, refNode){
25824 if(!refNode){ // like standard Dom, refNode can be null for append
25825 return this.appendChild(node);
25828 if(node == refNode){
25832 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
25835 var index = this.childNodes.indexOf(refNode);
25836 var oldParent = node.parentNode;
25837 var refIndex = index;
25839 // when moving internally, indexes will change after remove
25840 if(oldParent == this && this.childNodes.indexOf(node) < index){
25844 // it's a move, make sure we move it cleanly
25846 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
25849 oldParent.removeChild(node);
25852 this.setFirstChild(node);
25854 this.childNodes.splice(refIndex, 0, node);
25855 node.parentNode = this;
25856 var ps = this.childNodes[refIndex-1];
25858 node.previousSibling = ps;
25859 ps.nextSibling = node;
25861 node.previousSibling = null;
25863 node.nextSibling = refNode;
25864 refNode.previousSibling = node;
25865 node.setOwnerTree(this.getOwnerTree());
25866 this.fireEvent("insert", this.ownerTree, this, node, refNode);
25868 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
25874 * Returns the child node at the specified index.
25875 * @param {Number} index
25878 item : function(index){
25879 return this.childNodes[index];
25883 * Replaces one child node in this node with another.
25884 * @param {Node} newChild The replacement node
25885 * @param {Node} oldChild The node to replace
25886 * @return {Node} The replaced node
25888 replaceChild : function(newChild, oldChild){
25889 this.insertBefore(newChild, oldChild);
25890 this.removeChild(oldChild);
25895 * Returns the index of a child node
25896 * @param {Node} node
25897 * @return {Number} The index of the node or -1 if it was not found
25899 indexOf : function(child){
25900 return this.childNodes.indexOf(child);
25904 * Returns the tree this node is in.
25907 getOwnerTree : function(){
25908 // if it doesn't have one, look for one
25909 if(!this.ownerTree){
25913 this.ownerTree = p.ownerTree;
25919 return this.ownerTree;
25923 * Returns depth of this node (the root node has a depth of 0)
25926 getDepth : function(){
25929 while(p.parentNode){
25937 setOwnerTree : function(tree){
25938 // if it's move, we need to update everyone
25939 if(tree != this.ownerTree){
25940 if(this.ownerTree){
25941 this.ownerTree.unregisterNode(this);
25943 this.ownerTree = tree;
25944 var cs = this.childNodes;
25945 for(var i = 0, len = cs.length; i < len; i++) {
25946 cs[i].setOwnerTree(tree);
25949 tree.registerNode(this);
25955 * Returns the path for this node. The path can be used to expand or select this node programmatically.
25956 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
25957 * @return {String} The path
25959 getPath : function(attr){
25960 attr = attr || "id";
25961 var p = this.parentNode;
25962 var b = [this.attributes[attr]];
25964 b.unshift(p.attributes[attr]);
25967 var sep = this.getOwnerTree().pathSeparator;
25968 return sep + b.join(sep);
25972 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
25973 * function call will be the scope provided or the current node. The arguments to the function
25974 * will be the args provided or the current node. If the function returns false at any point,
25975 * the bubble is stopped.
25976 * @param {Function} fn The function to call
25977 * @param {Object} scope (optional) The scope of the function (defaults to current node)
25978 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
25980 bubble : function(fn, scope, args){
25983 if(fn.call(scope || p, args || p) === false){
25991 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
25992 * function call will be the scope provided or the current node. The arguments to the function
25993 * will be the args provided or the current node. If the function returns false at any point,
25994 * the cascade is stopped on that branch.
25995 * @param {Function} fn The function to call
25996 * @param {Object} scope (optional) The scope of the function (defaults to current node)
25997 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
25999 cascade : function(fn, scope, args){
26000 if(fn.call(scope || this, args || this) !== false){
26001 var cs = this.childNodes;
26002 for(var i = 0, len = cs.length; i < len; i++) {
26003 cs[i].cascade(fn, scope, args);
26009 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
26010 * function call will be the scope provided or the current node. The arguments to the function
26011 * will be the args provided or the current node. If the function returns false at any point,
26012 * the iteration stops.
26013 * @param {Function} fn The function to call
26014 * @param {Object} scope (optional) The scope of the function (defaults to current node)
26015 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
26017 eachChild : function(fn, scope, args){
26018 var cs = this.childNodes;
26019 for(var i = 0, len = cs.length; i < len; i++) {
26020 if(fn.call(scope || this, args || cs[i]) === false){
26027 * Finds the first child that has the attribute with the specified value.
26028 * @param {String} attribute The attribute name
26029 * @param {Mixed} value The value to search for
26030 * @return {Node} The found child or null if none was found
26032 findChild : function(attribute, value){
26033 var cs = this.childNodes;
26034 for(var i = 0, len = cs.length; i < len; i++) {
26035 if(cs[i].attributes[attribute] == value){
26043 * Finds the first child by a custom function. The child matches if the function passed
26045 * @param {Function} fn
26046 * @param {Object} scope (optional)
26047 * @return {Node} The found child or null if none was found
26049 findChildBy : function(fn, scope){
26050 var cs = this.childNodes;
26051 for(var i = 0, len = cs.length; i < len; i++) {
26052 if(fn.call(scope||cs[i], cs[i]) === true){
26060 * Sorts this nodes children using the supplied sort function
26061 * @param {Function} fn
26062 * @param {Object} scope (optional)
26064 sort : function(fn, scope){
26065 var cs = this.childNodes;
26066 var len = cs.length;
26068 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
26070 for(var i = 0; i < len; i++){
26072 n.previousSibling = cs[i-1];
26073 n.nextSibling = cs[i+1];
26075 this.setFirstChild(n);
26078 this.setLastChild(n);
26085 * Returns true if this node is an ancestor (at any point) of the passed node.
26086 * @param {Node} node
26087 * @return {Boolean}
26089 contains : function(node){
26090 return node.isAncestor(this);
26094 * Returns true if the passed node is an ancestor (at any point) of this node.
26095 * @param {Node} node
26096 * @return {Boolean}
26098 isAncestor : function(node){
26099 var p = this.parentNode;
26109 toString : function(){
26110 return "[Node"+(this.id?" "+this.id:"")+"]";
26114 * Ext JS Library 1.1.1
26115 * Copyright(c) 2006-2007, Ext JS, LLC.
26117 * Originally Released Under LGPL - original licence link has changed is not relivant.
26120 * <script type="text/javascript">
26125 * @class Roo.Shadow
26126 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
26127 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
26128 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
26130 * Create a new Shadow
26131 * @param {Object} config The config object
26133 Roo.Shadow = function(config){
26134 Roo.apply(this, config);
26135 if(typeof this.mode != "string"){
26136 this.mode = this.defaultMode;
26138 var o = this.offset, a = {h: 0};
26139 var rad = Math.floor(this.offset/2);
26140 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
26146 a.l -= this.offset + rad;
26147 a.t -= this.offset + rad;
26158 a.l -= (this.offset - rad);
26159 a.t -= this.offset + rad;
26161 a.w -= (this.offset - rad)*2;
26172 a.l -= (this.offset - rad);
26173 a.t -= (this.offset - rad);
26175 a.w -= (this.offset + rad + 1);
26176 a.h -= (this.offset + rad);
26185 Roo.Shadow.prototype = {
26187 * @cfg {String} mode
26188 * The shadow display mode. Supports the following options:<br />
26189 * sides: Shadow displays on both sides and bottom only<br />
26190 * frame: Shadow displays equally on all four sides<br />
26191 * drop: Traditional bottom-right drop shadow (default)
26194 * @cfg {String} offset
26195 * The number of pixels to offset the shadow from the element (defaults to 4)
26200 defaultMode: "drop",
26203 * Displays the shadow under the target element
26204 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
26206 show : function(target){
26207 target = Roo.get(target);
26209 this.el = Roo.Shadow.Pool.pull();
26210 if(this.el.dom.nextSibling != target.dom){
26211 this.el.insertBefore(target);
26214 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
26216 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
26219 target.getLeft(true),
26220 target.getTop(true),
26224 this.el.dom.style.display = "block";
26228 * Returns true if the shadow is visible, else false
26230 isVisible : function(){
26231 return this.el ? true : false;
26235 * Direct alignment when values are already available. Show must be called at least once before
26236 * calling this method to ensure it is initialized.
26237 * @param {Number} left The target element left position
26238 * @param {Number} top The target element top position
26239 * @param {Number} width The target element width
26240 * @param {Number} height The target element height
26242 realign : function(l, t, w, h){
26246 var a = this.adjusts, d = this.el.dom, s = d.style;
26248 s.left = (l+a.l)+"px";
26249 s.top = (t+a.t)+"px";
26250 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
26252 if(s.width != sws || s.height != shs){
26256 var cn = d.childNodes;
26257 var sww = Math.max(0, (sw-12))+"px";
26258 cn[0].childNodes[1].style.width = sww;
26259 cn[1].childNodes[1].style.width = sww;
26260 cn[2].childNodes[1].style.width = sww;
26261 cn[1].style.height = Math.max(0, (sh-12))+"px";
26267 * Hides this shadow
26271 this.el.dom.style.display = "none";
26272 Roo.Shadow.Pool.push(this.el);
26278 * Adjust the z-index of this shadow
26279 * @param {Number} zindex The new z-index
26281 setZIndex : function(z){
26284 this.el.setStyle("z-index", z);
26289 // Private utility class that manages the internal Shadow cache
26290 Roo.Shadow.Pool = function(){
26292 var markup = Roo.isIE ?
26293 '<div class="x-ie-shadow"></div>' :
26294 '<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>';
26297 var sh = p.shift();
26299 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
26300 sh.autoBoxAdjust = false;
26305 push : function(sh){
26311 * Ext JS Library 1.1.1
26312 * Copyright(c) 2006-2007, Ext JS, LLC.
26314 * Originally Released Under LGPL - original licence link has changed is not relivant.
26317 * <script type="text/javascript">
26322 * @class Roo.SplitBar
26323 * @extends Roo.util.Observable
26324 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
26328 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
26329 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
26330 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
26331 split.minSize = 100;
26332 split.maxSize = 600;
26333 split.animate = true;
26334 split.on('moved', splitterMoved);
26337 * Create a new SplitBar
26338 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
26339 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
26340 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
26341 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
26342 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
26343 position of the SplitBar).
26345 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
26348 this.el = Roo.get(dragElement, true);
26349 this.el.dom.unselectable = "on";
26351 this.resizingEl = Roo.get(resizingElement, true);
26355 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
26356 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
26359 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
26362 * The minimum size of the resizing element. (Defaults to 0)
26368 * The maximum size of the resizing element. (Defaults to 2000)
26371 this.maxSize = 2000;
26374 * Whether to animate the transition to the new size
26377 this.animate = false;
26380 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
26383 this.useShim = false;
26388 if(!existingProxy){
26390 this.proxy = Roo.SplitBar.createProxy(this.orientation);
26392 this.proxy = Roo.get(existingProxy).dom;
26395 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
26398 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
26401 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
26404 this.dragSpecs = {};
26407 * @private The adapter to use to positon and resize elements
26409 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
26410 this.adapter.init(this);
26412 if(this.orientation == Roo.SplitBar.HORIZONTAL){
26414 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
26415 this.el.addClass("x-splitbar-h");
26418 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
26419 this.el.addClass("x-splitbar-v");
26425 * Fires when the splitter is moved (alias for {@link #event-moved})
26426 * @param {Roo.SplitBar} this
26427 * @param {Number} newSize the new width or height
26432 * Fires when the splitter is moved
26433 * @param {Roo.SplitBar} this
26434 * @param {Number} newSize the new width or height
26438 * @event beforeresize
26439 * Fires before the splitter is dragged
26440 * @param {Roo.SplitBar} this
26442 "beforeresize" : true,
26444 "beforeapply" : true
26447 Roo.util.Observable.call(this);
26450 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
26451 onStartProxyDrag : function(x, y){
26452 this.fireEvent("beforeresize", this);
26454 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
26456 o.enableDisplayMode("block");
26457 // all splitbars share the same overlay
26458 Roo.SplitBar.prototype.overlay = o;
26460 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
26461 this.overlay.show();
26462 Roo.get(this.proxy).setDisplayed("block");
26463 var size = this.adapter.getElementSize(this);
26464 this.activeMinSize = this.getMinimumSize();;
26465 this.activeMaxSize = this.getMaximumSize();;
26466 var c1 = size - this.activeMinSize;
26467 var c2 = Math.max(this.activeMaxSize - size, 0);
26468 if(this.orientation == Roo.SplitBar.HORIZONTAL){
26469 this.dd.resetConstraints();
26470 this.dd.setXConstraint(
26471 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
26472 this.placement == Roo.SplitBar.LEFT ? c2 : c1
26474 this.dd.setYConstraint(0, 0);
26476 this.dd.resetConstraints();
26477 this.dd.setXConstraint(0, 0);
26478 this.dd.setYConstraint(
26479 this.placement == Roo.SplitBar.TOP ? c1 : c2,
26480 this.placement == Roo.SplitBar.TOP ? c2 : c1
26483 this.dragSpecs.startSize = size;
26484 this.dragSpecs.startPoint = [x, y];
26485 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
26489 * @private Called after the drag operation by the DDProxy
26491 onEndProxyDrag : function(e){
26492 Roo.get(this.proxy).setDisplayed(false);
26493 var endPoint = Roo.lib.Event.getXY(e);
26495 this.overlay.hide();
26498 if(this.orientation == Roo.SplitBar.HORIZONTAL){
26499 newSize = this.dragSpecs.startSize +
26500 (this.placement == Roo.SplitBar.LEFT ?
26501 endPoint[0] - this.dragSpecs.startPoint[0] :
26502 this.dragSpecs.startPoint[0] - endPoint[0]
26505 newSize = this.dragSpecs.startSize +
26506 (this.placement == Roo.SplitBar.TOP ?
26507 endPoint[1] - this.dragSpecs.startPoint[1] :
26508 this.dragSpecs.startPoint[1] - endPoint[1]
26511 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
26512 if(newSize != this.dragSpecs.startSize){
26513 if(this.fireEvent('beforeapply', this, newSize) !== false){
26514 this.adapter.setElementSize(this, newSize);
26515 this.fireEvent("moved", this, newSize);
26516 this.fireEvent("resize", this, newSize);
26522 * Get the adapter this SplitBar uses
26523 * @return The adapter object
26525 getAdapter : function(){
26526 return this.adapter;
26530 * Set the adapter this SplitBar uses
26531 * @param {Object} adapter A SplitBar adapter object
26533 setAdapter : function(adapter){
26534 this.adapter = adapter;
26535 this.adapter.init(this);
26539 * Gets the minimum size for the resizing element
26540 * @return {Number} The minimum size
26542 getMinimumSize : function(){
26543 return this.minSize;
26547 * Sets the minimum size for the resizing element
26548 * @param {Number} minSize The minimum size
26550 setMinimumSize : function(minSize){
26551 this.minSize = minSize;
26555 * Gets the maximum size for the resizing element
26556 * @return {Number} The maximum size
26558 getMaximumSize : function(){
26559 return this.maxSize;
26563 * Sets the maximum size for the resizing element
26564 * @param {Number} maxSize The maximum size
26566 setMaximumSize : function(maxSize){
26567 this.maxSize = maxSize;
26571 * Sets the initialize size for the resizing element
26572 * @param {Number} size The initial size
26574 setCurrentSize : function(size){
26575 var oldAnimate = this.animate;
26576 this.animate = false;
26577 this.adapter.setElementSize(this, size);
26578 this.animate = oldAnimate;
26582 * Destroy this splitbar.
26583 * @param {Boolean} removeEl True to remove the element
26585 destroy : function(removeEl){
26587 this.shim.remove();
26590 this.proxy.parentNode.removeChild(this.proxy);
26598 * @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.
26600 Roo.SplitBar.createProxy = function(dir){
26601 var proxy = new Roo.Element(document.createElement("div"));
26602 proxy.unselectable();
26603 var cls = 'x-splitbar-proxy';
26604 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
26605 document.body.appendChild(proxy.dom);
26610 * @class Roo.SplitBar.BasicLayoutAdapter
26611 * Default Adapter. It assumes the splitter and resizing element are not positioned
26612 * elements and only gets/sets the width of the element. Generally used for table based layouts.
26614 Roo.SplitBar.BasicLayoutAdapter = function(){
26617 Roo.SplitBar.BasicLayoutAdapter.prototype = {
26618 // do nothing for now
26619 init : function(s){
26623 * Called before drag operations to get the current size of the resizing element.
26624 * @param {Roo.SplitBar} s The SplitBar using this adapter
26626 getElementSize : function(s){
26627 if(s.orientation == Roo.SplitBar.HORIZONTAL){
26628 return s.resizingEl.getWidth();
26630 return s.resizingEl.getHeight();
26635 * Called after drag operations to set the size of the resizing element.
26636 * @param {Roo.SplitBar} s The SplitBar using this adapter
26637 * @param {Number} newSize The new size to set
26638 * @param {Function} onComplete A function to be invoked when resizing is complete
26640 setElementSize : function(s, newSize, onComplete){
26641 if(s.orientation == Roo.SplitBar.HORIZONTAL){
26643 s.resizingEl.setWidth(newSize);
26645 onComplete(s, newSize);
26648 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
26653 s.resizingEl.setHeight(newSize);
26655 onComplete(s, newSize);
26658 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
26665 *@class Roo.SplitBar.AbsoluteLayoutAdapter
26666 * @extends Roo.SplitBar.BasicLayoutAdapter
26667 * Adapter that moves the splitter element to align with the resized sizing element.
26668 * Used with an absolute positioned SplitBar.
26669 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
26670 * document.body, make sure you assign an id to the body element.
26672 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
26673 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
26674 this.container = Roo.get(container);
26677 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
26678 init : function(s){
26679 this.basic.init(s);
26682 getElementSize : function(s){
26683 return this.basic.getElementSize(s);
26686 setElementSize : function(s, newSize, onComplete){
26687 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
26690 moveSplitter : function(s){
26691 var yes = Roo.SplitBar;
26692 switch(s.placement){
26694 s.el.setX(s.resizingEl.getRight());
26697 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
26700 s.el.setY(s.resizingEl.getBottom());
26703 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
26710 * Orientation constant - Create a vertical SplitBar
26714 Roo.SplitBar.VERTICAL = 1;
26717 * Orientation constant - Create a horizontal SplitBar
26721 Roo.SplitBar.HORIZONTAL = 2;
26724 * Placement constant - The resizing element is to the left of the splitter element
26728 Roo.SplitBar.LEFT = 1;
26731 * Placement constant - The resizing element is to the right of the splitter element
26735 Roo.SplitBar.RIGHT = 2;
26738 * Placement constant - The resizing element is positioned above the splitter element
26742 Roo.SplitBar.TOP = 3;
26745 * Placement constant - The resizing element is positioned under splitter element
26749 Roo.SplitBar.BOTTOM = 4;
26752 * Ext JS Library 1.1.1
26753 * Copyright(c) 2006-2007, Ext JS, LLC.
26755 * Originally Released Under LGPL - original licence link has changed is not relivant.
26758 * <script type="text/javascript">
26763 * @extends Roo.util.Observable
26764 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
26765 * This class also supports single and multi selection modes. <br>
26766 * Create a data model bound view:
26768 var store = new Roo.data.Store(...);
26770 var view = new Roo.View({
26772 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
26774 singleSelect: true,
26775 selectedClass: "ydataview-selected",
26779 // listen for node click?
26780 view.on("click", function(vw, index, node, e){
26781 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
26785 dataModel.load("foobar.xml");
26787 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
26789 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
26790 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
26792 * Note: old style constructor is still suported (container, template, config)
26795 * Create a new View
26796 * @param {Object} config The config object
26799 Roo.View = function(config, depreciated_tpl, depreciated_config){
26801 this.parent = false;
26803 if (typeof(depreciated_tpl) == 'undefined') {
26804 // new way.. - universal constructor.
26805 Roo.apply(this, config);
26806 this.el = Roo.get(this.el);
26809 this.el = Roo.get(config);
26810 this.tpl = depreciated_tpl;
26811 Roo.apply(this, depreciated_config);
26813 this.wrapEl = this.el.wrap().wrap();
26814 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
26817 if(typeof(this.tpl) == "string"){
26818 this.tpl = new Roo.Template(this.tpl);
26820 // support xtype ctors..
26821 this.tpl = new Roo.factory(this.tpl, Roo);
26825 this.tpl.compile();
26830 * @event beforeclick
26831 * Fires before a click is processed. Returns false to cancel the default action.
26832 * @param {Roo.View} this
26833 * @param {Number} index The index of the target node
26834 * @param {HTMLElement} node The target node
26835 * @param {Roo.EventObject} e The raw event object
26837 "beforeclick" : true,
26840 * Fires when a template node is clicked.
26841 * @param {Roo.View} this
26842 * @param {Number} index The index of the target node
26843 * @param {HTMLElement} node The target node
26844 * @param {Roo.EventObject} e The raw event object
26849 * Fires when a template node is double clicked.
26850 * @param {Roo.View} this
26851 * @param {Number} index The index of the target node
26852 * @param {HTMLElement} node The target node
26853 * @param {Roo.EventObject} e The raw event object
26857 * @event contextmenu
26858 * Fires when a template node is right clicked.
26859 * @param {Roo.View} this
26860 * @param {Number} index The index of the target node
26861 * @param {HTMLElement} node The target node
26862 * @param {Roo.EventObject} e The raw event object
26864 "contextmenu" : true,
26866 * @event selectionchange
26867 * Fires when the selected nodes change.
26868 * @param {Roo.View} this
26869 * @param {Array} selections Array of the selected nodes
26871 "selectionchange" : true,
26874 * @event beforeselect
26875 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
26876 * @param {Roo.View} this
26877 * @param {HTMLElement} node The node to be selected
26878 * @param {Array} selections Array of currently selected nodes
26880 "beforeselect" : true,
26882 * @event preparedata
26883 * Fires on every row to render, to allow you to change the data.
26884 * @param {Roo.View} this
26885 * @param {Object} data to be rendered (change this)
26887 "preparedata" : true
26895 "click": this.onClick,
26896 "dblclick": this.onDblClick,
26897 "contextmenu": this.onContextMenu,
26901 this.selections = [];
26903 this.cmp = new Roo.CompositeElementLite([]);
26905 this.store = Roo.factory(this.store, Roo.data);
26906 this.setStore(this.store, true);
26909 if ( this.footer && this.footer.xtype) {
26911 var fctr = this.wrapEl.appendChild(document.createElement("div"));
26913 this.footer.dataSource = this.store;
26914 this.footer.container = fctr;
26915 this.footer = Roo.factory(this.footer, Roo);
26916 fctr.insertFirst(this.el);
26918 // this is a bit insane - as the paging toolbar seems to detach the el..
26919 // dom.parentNode.parentNode.parentNode
26920 // they get detached?
26924 Roo.View.superclass.constructor.call(this);
26929 Roo.extend(Roo.View, Roo.util.Observable, {
26932 * @cfg {Roo.data.Store} store Data store to load data from.
26937 * @cfg {String|Roo.Element} el The container element.
26942 * @cfg {String|Roo.Template} tpl The template used by this View
26946 * @cfg {String} dataName the named area of the template to use as the data area
26947 * Works with domtemplates roo-name="name"
26951 * @cfg {String} selectedClass The css class to add to selected nodes
26953 selectedClass : "x-view-selected",
26955 * @cfg {String} emptyText The empty text to show when nothing is loaded.
26960 * @cfg {String} text to display on mask (default Loading)
26964 * @cfg {Boolean} multiSelect Allow multiple selection
26966 multiSelect : false,
26968 * @cfg {Boolean} singleSelect Allow single selection
26970 singleSelect: false,
26973 * @cfg {Boolean} toggleSelect - selecting
26975 toggleSelect : false,
26978 * @cfg {Boolean} tickable - selecting
26983 * Returns the element this view is bound to.
26984 * @return {Roo.Element}
26986 getEl : function(){
26987 return this.wrapEl;
26993 * Refreshes the view. - called by datachanged on the store. - do not call directly.
26995 refresh : function(){
26996 //Roo.log('refresh');
26999 // if we are using something like 'domtemplate', then
27000 // the what gets used is:
27001 // t.applySubtemplate(NAME, data, wrapping data..)
27002 // the outer template then get' applied with
27003 // the store 'extra data'
27004 // and the body get's added to the
27005 // roo-name="data" node?
27006 // <span class='roo-tpl-{name}'></span> ?????
27010 this.clearSelections();
27011 this.el.update("");
27013 var records = this.store.getRange();
27014 if(records.length < 1) {
27016 // is this valid?? = should it render a template??
27018 this.el.update(this.emptyText);
27022 if (this.dataName) {
27023 this.el.update(t.apply(this.store.meta)); //????
27024 el = this.el.child('.roo-tpl-' + this.dataName);
27027 for(var i = 0, len = records.length; i < len; i++){
27028 var data = this.prepareData(records[i].data, i, records[i]);
27029 this.fireEvent("preparedata", this, data, i, records[i]);
27031 var d = Roo.apply({}, data);
27034 Roo.apply(d, {'roo-id' : Roo.id()});
27038 Roo.each(this.parent.item, function(item){
27039 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
27042 Roo.apply(d, {'roo-data-checked' : 'checked'});
27046 html[html.length] = Roo.util.Format.trim(
27048 t.applySubtemplate(this.dataName, d, this.store.meta) :
27055 el.update(html.join(""));
27056 this.nodes = el.dom.childNodes;
27057 this.updateIndexes(0);
27062 * Function to override to reformat the data that is sent to
27063 * the template for each node.
27064 * DEPRICATED - use the preparedata event handler.
27065 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
27066 * a JSON object for an UpdateManager bound view).
27068 prepareData : function(data, index, record)
27070 this.fireEvent("preparedata", this, data, index, record);
27074 onUpdate : function(ds, record){
27075 // Roo.log('on update');
27076 this.clearSelections();
27077 var index = this.store.indexOf(record);
27078 var n = this.nodes[index];
27079 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
27080 n.parentNode.removeChild(n);
27081 this.updateIndexes(index, index);
27087 onAdd : function(ds, records, index)
27089 //Roo.log(['on Add', ds, records, index] );
27090 this.clearSelections();
27091 if(this.nodes.length == 0){
27095 var n = this.nodes[index];
27096 for(var i = 0, len = records.length; i < len; i++){
27097 var d = this.prepareData(records[i].data, i, records[i]);
27099 this.tpl.insertBefore(n, d);
27102 this.tpl.append(this.el, d);
27105 this.updateIndexes(index);
27108 onRemove : function(ds, record, index){
27109 // Roo.log('onRemove');
27110 this.clearSelections();
27111 var el = this.dataName ?
27112 this.el.child('.roo-tpl-' + this.dataName) :
27115 el.dom.removeChild(this.nodes[index]);
27116 this.updateIndexes(index);
27120 * Refresh an individual node.
27121 * @param {Number} index
27123 refreshNode : function(index){
27124 this.onUpdate(this.store, this.store.getAt(index));
27127 updateIndexes : function(startIndex, endIndex){
27128 var ns = this.nodes;
27129 startIndex = startIndex || 0;
27130 endIndex = endIndex || ns.length - 1;
27131 for(var i = startIndex; i <= endIndex; i++){
27132 ns[i].nodeIndex = i;
27137 * Changes the data store this view uses and refresh the view.
27138 * @param {Store} store
27140 setStore : function(store, initial){
27141 if(!initial && this.store){
27142 this.store.un("datachanged", this.refresh);
27143 this.store.un("add", this.onAdd);
27144 this.store.un("remove", this.onRemove);
27145 this.store.un("update", this.onUpdate);
27146 this.store.un("clear", this.refresh);
27147 this.store.un("beforeload", this.onBeforeLoad);
27148 this.store.un("load", this.onLoad);
27149 this.store.un("loadexception", this.onLoad);
27153 store.on("datachanged", this.refresh, this);
27154 store.on("add", this.onAdd, this);
27155 store.on("remove", this.onRemove, this);
27156 store.on("update", this.onUpdate, this);
27157 store.on("clear", this.refresh, this);
27158 store.on("beforeload", this.onBeforeLoad, this);
27159 store.on("load", this.onLoad, this);
27160 store.on("loadexception", this.onLoad, this);
27168 * onbeforeLoad - masks the loading area.
27171 onBeforeLoad : function(store,opts)
27173 //Roo.log('onBeforeLoad');
27175 this.el.update("");
27177 this.el.mask(this.mask ? this.mask : "Loading" );
27179 onLoad : function ()
27186 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
27187 * @param {HTMLElement} node
27188 * @return {HTMLElement} The template node
27190 findItemFromChild : function(node){
27191 var el = this.dataName ?
27192 this.el.child('.roo-tpl-' + this.dataName,true) :
27195 if(!node || node.parentNode == el){
27198 var p = node.parentNode;
27199 while(p && p != el){
27200 if(p.parentNode == el){
27209 onClick : function(e){
27210 var item = this.findItemFromChild(e.getTarget());
27212 var index = this.indexOf(item);
27213 if(this.onItemClick(item, index, e) !== false){
27214 this.fireEvent("click", this, index, item, e);
27217 this.clearSelections();
27222 onContextMenu : function(e){
27223 var item = this.findItemFromChild(e.getTarget());
27225 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
27230 onDblClick : function(e){
27231 var item = this.findItemFromChild(e.getTarget());
27233 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
27237 onItemClick : function(item, index, e)
27239 if(this.fireEvent("beforeclick", this, index, item, e) === false){
27242 if (this.toggleSelect) {
27243 var m = this.isSelected(item) ? 'unselect' : 'select';
27246 _t[m](item, true, false);
27249 if(this.multiSelect || this.singleSelect){
27250 if(this.multiSelect && e.shiftKey && this.lastSelection){
27251 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
27253 this.select(item, this.multiSelect && e.ctrlKey);
27254 this.lastSelection = item;
27257 if(!this.tickable){
27258 e.preventDefault();
27266 * Get the number of selected nodes.
27269 getSelectionCount : function(){
27270 return this.selections.length;
27274 * Get the currently selected nodes.
27275 * @return {Array} An array of HTMLElements
27277 getSelectedNodes : function(){
27278 return this.selections;
27282 * Get the indexes of the selected nodes.
27285 getSelectedIndexes : function(){
27286 var indexes = [], s = this.selections;
27287 for(var i = 0, len = s.length; i < len; i++){
27288 indexes.push(s[i].nodeIndex);
27294 * Clear all selections
27295 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
27297 clearSelections : function(suppressEvent){
27298 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
27299 this.cmp.elements = this.selections;
27300 this.cmp.removeClass(this.selectedClass);
27301 this.selections = [];
27302 if(!suppressEvent){
27303 this.fireEvent("selectionchange", this, this.selections);
27309 * Returns true if the passed node is selected
27310 * @param {HTMLElement/Number} node The node or node index
27311 * @return {Boolean}
27313 isSelected : function(node){
27314 var s = this.selections;
27318 node = this.getNode(node);
27319 return s.indexOf(node) !== -1;
27324 * @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
27325 * @param {Boolean} keepExisting (optional) true to keep existing selections
27326 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
27328 select : function(nodeInfo, keepExisting, suppressEvent){
27329 if(nodeInfo instanceof Array){
27331 this.clearSelections(true);
27333 for(var i = 0, len = nodeInfo.length; i < len; i++){
27334 this.select(nodeInfo[i], true, true);
27338 var node = this.getNode(nodeInfo);
27339 if(!node || this.isSelected(node)){
27340 return; // already selected.
27343 this.clearSelections(true);
27346 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
27347 Roo.fly(node).addClass(this.selectedClass);
27348 this.selections.push(node);
27349 if(!suppressEvent){
27350 this.fireEvent("selectionchange", this, this.selections);
27358 * @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
27359 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
27360 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
27362 unselect : function(nodeInfo, keepExisting, suppressEvent)
27364 if(nodeInfo instanceof Array){
27365 Roo.each(this.selections, function(s) {
27366 this.unselect(s, nodeInfo);
27370 var node = this.getNode(nodeInfo);
27371 if(!node || !this.isSelected(node)){
27372 //Roo.log("not selected");
27373 return; // not selected.
27377 Roo.each(this.selections, function(s) {
27379 Roo.fly(node).removeClass(this.selectedClass);
27386 this.selections= ns;
27387 this.fireEvent("selectionchange", this, this.selections);
27391 * Gets a template node.
27392 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
27393 * @return {HTMLElement} The node or null if it wasn't found
27395 getNode : function(nodeInfo){
27396 if(typeof nodeInfo == "string"){
27397 return document.getElementById(nodeInfo);
27398 }else if(typeof nodeInfo == "number"){
27399 return this.nodes[nodeInfo];
27405 * Gets a range template nodes.
27406 * @param {Number} startIndex
27407 * @param {Number} endIndex
27408 * @return {Array} An array of nodes
27410 getNodes : function(start, end){
27411 var ns = this.nodes;
27412 start = start || 0;
27413 end = typeof end == "undefined" ? ns.length - 1 : end;
27416 for(var i = start; i <= end; i++){
27420 for(var i = start; i >= end; i--){
27428 * Finds the index of the passed node
27429 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
27430 * @return {Number} The index of the node or -1
27432 indexOf : function(node){
27433 node = this.getNode(node);
27434 if(typeof node.nodeIndex == "number"){
27435 return node.nodeIndex;
27437 var ns = this.nodes;
27438 for(var i = 0, len = ns.length; i < len; i++){
27448 * Ext JS Library 1.1.1
27449 * Copyright(c) 2006-2007, Ext JS, LLC.
27451 * Originally Released Under LGPL - original licence link has changed is not relivant.
27454 * <script type="text/javascript">
27458 * @class Roo.JsonView
27459 * @extends Roo.View
27460 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
27462 var view = new Roo.JsonView({
27463 container: "my-element",
27464 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
27469 // listen for node click?
27470 view.on("click", function(vw, index, node, e){
27471 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
27474 // direct load of JSON data
27475 view.load("foobar.php");
27477 // Example from my blog list
27478 var tpl = new Roo.Template(
27479 '<div class="entry">' +
27480 '<a class="entry-title" href="{link}">{title}</a>' +
27481 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
27482 "</div><hr />"
27485 var moreView = new Roo.JsonView({
27486 container : "entry-list",
27490 moreView.on("beforerender", this.sortEntries, this);
27492 url: "/blog/get-posts.php",
27493 params: "allposts=true",
27494 text: "Loading Blog Entries..."
27498 * Note: old code is supported with arguments : (container, template, config)
27502 * Create a new JsonView
27504 * @param {Object} config The config object
27507 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
27510 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
27512 var um = this.el.getUpdateManager();
27513 um.setRenderer(this);
27514 um.on("update", this.onLoad, this);
27515 um.on("failure", this.onLoadException, this);
27518 * @event beforerender
27519 * Fires before rendering of the downloaded JSON data.
27520 * @param {Roo.JsonView} this
27521 * @param {Object} data The JSON data loaded
27525 * Fires when data is loaded.
27526 * @param {Roo.JsonView} this
27527 * @param {Object} data The JSON data loaded
27528 * @param {Object} response The raw Connect response object
27531 * @event loadexception
27532 * Fires when loading fails.
27533 * @param {Roo.JsonView} this
27534 * @param {Object} response The raw Connect response object
27537 'beforerender' : true,
27539 'loadexception' : true
27542 Roo.extend(Roo.JsonView, Roo.View, {
27544 * @type {String} The root property in the loaded JSON object that contains the data
27549 * Refreshes the view.
27551 refresh : function(){
27552 this.clearSelections();
27553 this.el.update("");
27555 var o = this.jsonData;
27556 if(o && o.length > 0){
27557 for(var i = 0, len = o.length; i < len; i++){
27558 var data = this.prepareData(o[i], i, o);
27559 html[html.length] = this.tpl.apply(data);
27562 html.push(this.emptyText);
27564 this.el.update(html.join(""));
27565 this.nodes = this.el.dom.childNodes;
27566 this.updateIndexes(0);
27570 * 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.
27571 * @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:
27574 url: "your-url.php",
27575 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
27576 callback: yourFunction,
27577 scope: yourObject, //(optional scope)
27580 text: "Loading...",
27585 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
27586 * 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.
27587 * @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}
27588 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
27589 * @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.
27592 var um = this.el.getUpdateManager();
27593 um.update.apply(um, arguments);
27596 // note - render is a standard framework call...
27597 // using it for the response is really flaky... - it's called by UpdateManager normally, except when called by the XComponent/addXtype.
27598 render : function(el, response){
27600 this.clearSelections();
27601 this.el.update("");
27604 if (response != '') {
27605 o = Roo.util.JSON.decode(response.responseText);
27608 o = o[this.jsonRoot];
27614 * The current JSON data or null
27617 this.beforeRender();
27622 * Get the number of records in the current JSON dataset
27625 getCount : function(){
27626 return this.jsonData ? this.jsonData.length : 0;
27630 * Returns the JSON object for the specified node(s)
27631 * @param {HTMLElement/Array} node The node or an array of nodes
27632 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
27633 * you get the JSON object for the node
27635 getNodeData : function(node){
27636 if(node instanceof Array){
27638 for(var i = 0, len = node.length; i < len; i++){
27639 data.push(this.getNodeData(node[i]));
27643 return this.jsonData[this.indexOf(node)] || null;
27646 beforeRender : function(){
27647 this.snapshot = this.jsonData;
27649 this.sort.apply(this, this.sortInfo);
27651 this.fireEvent("beforerender", this, this.jsonData);
27654 onLoad : function(el, o){
27655 this.fireEvent("load", this, this.jsonData, o);
27658 onLoadException : function(el, o){
27659 this.fireEvent("loadexception", this, o);
27663 * Filter the data by a specific property.
27664 * @param {String} property A property on your JSON objects
27665 * @param {String/RegExp} value Either string that the property values
27666 * should start with, or a RegExp to test against the property
27668 filter : function(property, value){
27671 var ss = this.snapshot;
27672 if(typeof value == "string"){
27673 var vlen = value.length;
27675 this.clearFilter();
27678 value = value.toLowerCase();
27679 for(var i = 0, len = ss.length; i < len; i++){
27681 if(o[property].substr(0, vlen).toLowerCase() == value){
27685 } else if(value.exec){ // regex?
27686 for(var i = 0, len = ss.length; i < len; i++){
27688 if(value.test(o[property])){
27695 this.jsonData = data;
27701 * Filter by a function. The passed function will be called with each
27702 * object in the current dataset. If the function returns true the value is kept,
27703 * otherwise it is filtered.
27704 * @param {Function} fn
27705 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
27707 filterBy : function(fn, scope){
27710 var ss = this.snapshot;
27711 for(var i = 0, len = ss.length; i < len; i++){
27713 if(fn.call(scope || this, o)){
27717 this.jsonData = data;
27723 * Clears the current filter.
27725 clearFilter : function(){
27726 if(this.snapshot && this.jsonData != this.snapshot){
27727 this.jsonData = this.snapshot;
27734 * Sorts the data for this view and refreshes it.
27735 * @param {String} property A property on your JSON objects to sort on
27736 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
27737 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
27739 sort : function(property, dir, sortType){
27740 this.sortInfo = Array.prototype.slice.call(arguments, 0);
27743 var dsc = dir && dir.toLowerCase() == "desc";
27744 var f = function(o1, o2){
27745 var v1 = sortType ? sortType(o1[p]) : o1[p];
27746 var v2 = sortType ? sortType(o2[p]) : o2[p];
27749 return dsc ? +1 : -1;
27750 } else if(v1 > v2){
27751 return dsc ? -1 : +1;
27756 this.jsonData.sort(f);
27758 if(this.jsonData != this.snapshot){
27759 this.snapshot.sort(f);
27765 * Ext JS Library 1.1.1
27766 * Copyright(c) 2006-2007, Ext JS, LLC.
27768 * Originally Released Under LGPL - original licence link has changed is not relivant.
27771 * <script type="text/javascript">
27776 * @class Roo.ColorPalette
27777 * @extends Roo.Component
27778 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
27779 * Here's an example of typical usage:
27781 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
27782 cp.render('my-div');
27784 cp.on('select', function(palette, selColor){
27785 // do something with selColor
27789 * Create a new ColorPalette
27790 * @param {Object} config The config object
27792 Roo.ColorPalette = function(config){
27793 Roo.ColorPalette.superclass.constructor.call(this, config);
27797 * Fires when a color is selected
27798 * @param {ColorPalette} this
27799 * @param {String} color The 6-digit color hex code (without the # symbol)
27805 this.on("select", this.handler, this.scope, true);
27808 Roo.extend(Roo.ColorPalette, Roo.Component, {
27810 * @cfg {String} itemCls
27811 * The CSS class to apply to the containing element (defaults to "x-color-palette")
27813 itemCls : "x-color-palette",
27815 * @cfg {String} value
27816 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
27817 * the hex codes are case-sensitive.
27820 clickEvent:'click',
27822 ctype: "Roo.ColorPalette",
27825 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
27827 allowReselect : false,
27830 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
27831 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
27832 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
27833 * of colors with the width setting until the box is symmetrical.</p>
27834 * <p>You can override individual colors if needed:</p>
27836 var cp = new Roo.ColorPalette();
27837 cp.colors[0] = "FF0000"; // change the first box to red
27840 Or you can provide a custom array of your own for complete control:
27842 var cp = new Roo.ColorPalette();
27843 cp.colors = ["000000", "993300", "333300"];
27848 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
27849 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
27850 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
27851 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
27852 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
27856 onRender : function(container, position){
27857 var t = new Roo.MasterTemplate(
27858 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
27860 var c = this.colors;
27861 for(var i = 0, len = c.length; i < len; i++){
27864 var el = document.createElement("div");
27865 el.className = this.itemCls;
27867 container.dom.insertBefore(el, position);
27868 this.el = Roo.get(el);
27869 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
27870 if(this.clickEvent != 'click'){
27871 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
27876 afterRender : function(){
27877 Roo.ColorPalette.superclass.afterRender.call(this);
27879 var s = this.value;
27886 handleClick : function(e, t){
27887 e.preventDefault();
27888 if(!this.disabled){
27889 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
27890 this.select(c.toUpperCase());
27895 * Selects the specified color in the palette (fires the select event)
27896 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
27898 select : function(color){
27899 color = color.replace("#", "");
27900 if(color != this.value || this.allowReselect){
27903 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
27905 el.child("a.color-"+color).addClass("x-color-palette-sel");
27906 this.value = color;
27907 this.fireEvent("select", this, color);
27912 * Ext JS Library 1.1.1
27913 * Copyright(c) 2006-2007, Ext JS, LLC.
27915 * Originally Released Under LGPL - original licence link has changed is not relivant.
27918 * <script type="text/javascript">
27922 * @class Roo.DatePicker
27923 * @extends Roo.Component
27924 * Simple date picker class.
27926 * Create a new DatePicker
27927 * @param {Object} config The config object
27929 Roo.DatePicker = function(config){
27930 Roo.DatePicker.superclass.constructor.call(this, config);
27932 this.value = config && config.value ?
27933 config.value.clearTime() : new Date().clearTime();
27938 * Fires when a date is selected
27939 * @param {DatePicker} this
27940 * @param {Date} date The selected date
27944 * @event monthchange
27945 * Fires when the displayed month changes
27946 * @param {DatePicker} this
27947 * @param {Date} date The selected month
27949 'monthchange': true
27953 this.on("select", this.handler, this.scope || this);
27955 // build the disabledDatesRE
27956 if(!this.disabledDatesRE && this.disabledDates){
27957 var dd = this.disabledDates;
27959 for(var i = 0; i < dd.length; i++){
27961 if(i != dd.length-1) {
27965 this.disabledDatesRE = new RegExp(re + ")");
27969 Roo.extend(Roo.DatePicker, Roo.Component, {
27971 * @cfg {String} todayText
27972 * The text to display on the button that selects the current date (defaults to "Today")
27974 todayText : "Today",
27976 * @cfg {String} okText
27977 * The text to display on the ok button
27979 okText : " OK ", //   to give the user extra clicking room
27981 * @cfg {String} cancelText
27982 * The text to display on the cancel button
27984 cancelText : "Cancel",
27986 * @cfg {String} todayTip
27987 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
27989 todayTip : "{0} (Spacebar)",
27991 * @cfg {Date} minDate
27992 * Minimum allowable date (JavaScript date object, defaults to null)
27996 * @cfg {Date} maxDate
27997 * Maximum allowable date (JavaScript date object, defaults to null)
28001 * @cfg {String} minText
28002 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
28004 minText : "This date is before the minimum date",
28006 * @cfg {String} maxText
28007 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
28009 maxText : "This date is after the maximum date",
28011 * @cfg {String} format
28012 * The default date format string which can be overriden for localization support. The format must be
28013 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
28017 * @cfg {Array} disabledDays
28018 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
28020 disabledDays : null,
28022 * @cfg {String} disabledDaysText
28023 * The tooltip to display when the date falls on a disabled day (defaults to "")
28025 disabledDaysText : "",
28027 * @cfg {RegExp} disabledDatesRE
28028 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
28030 disabledDatesRE : null,
28032 * @cfg {String} disabledDatesText
28033 * The tooltip text to display when the date falls on a disabled date (defaults to "")
28035 disabledDatesText : "",
28037 * @cfg {Boolean} constrainToViewport
28038 * True to constrain the date picker to the viewport (defaults to true)
28040 constrainToViewport : true,
28042 * @cfg {Array} monthNames
28043 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
28045 monthNames : Date.monthNames,
28047 * @cfg {Array} dayNames
28048 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
28050 dayNames : Date.dayNames,
28052 * @cfg {String} nextText
28053 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
28055 nextText: 'Next Month (Control+Right)',
28057 * @cfg {String} prevText
28058 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
28060 prevText: 'Previous Month (Control+Left)',
28062 * @cfg {String} monthYearText
28063 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
28065 monthYearText: 'Choose a month (Control+Up/Down to move years)',
28067 * @cfg {Number} startDay
28068 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
28072 * @cfg {Bool} showClear
28073 * Show a clear button (usefull for date form elements that can be blank.)
28079 * Sets the value of the date field
28080 * @param {Date} value The date to set
28082 setValue : function(value){
28083 var old = this.value;
28085 if (typeof(value) == 'string') {
28087 value = Date.parseDate(value, this.format);
28090 value = new Date();
28093 this.value = value.clearTime(true);
28095 this.update(this.value);
28100 * Gets the current selected value of the date field
28101 * @return {Date} The selected date
28103 getValue : function(){
28108 focus : function(){
28110 this.update(this.activeDate);
28115 onRender : function(container, position){
28118 '<table cellspacing="0">',
28119 '<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>',
28120 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
28121 var dn = this.dayNames;
28122 for(var i = 0; i < 7; i++){
28123 var d = this.startDay+i;
28127 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
28129 m[m.length] = "</tr></thead><tbody><tr>";
28130 for(var i = 0; i < 42; i++) {
28131 if(i % 7 == 0 && i != 0){
28132 m[m.length] = "</tr><tr>";
28134 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
28136 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
28137 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
28139 var el = document.createElement("div");
28140 el.className = "x-date-picker";
28141 el.innerHTML = m.join("");
28143 container.dom.insertBefore(el, position);
28145 this.el = Roo.get(el);
28146 this.eventEl = Roo.get(el.firstChild);
28148 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
28149 handler: this.showPrevMonth,
28151 preventDefault:true,
28155 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
28156 handler: this.showNextMonth,
28158 preventDefault:true,
28162 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
28164 this.monthPicker = this.el.down('div.x-date-mp');
28165 this.monthPicker.enableDisplayMode('block');
28167 var kn = new Roo.KeyNav(this.eventEl, {
28168 "left" : function(e){
28170 this.showPrevMonth() :
28171 this.update(this.activeDate.add("d", -1));
28174 "right" : function(e){
28176 this.showNextMonth() :
28177 this.update(this.activeDate.add("d", 1));
28180 "up" : function(e){
28182 this.showNextYear() :
28183 this.update(this.activeDate.add("d", -7));
28186 "down" : function(e){
28188 this.showPrevYear() :
28189 this.update(this.activeDate.add("d", 7));
28192 "pageUp" : function(e){
28193 this.showNextMonth();
28196 "pageDown" : function(e){
28197 this.showPrevMonth();
28200 "enter" : function(e){
28201 e.stopPropagation();
28208 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
28210 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
28212 this.el.unselectable();
28214 this.cells = this.el.select("table.x-date-inner tbody td");
28215 this.textNodes = this.el.query("table.x-date-inner tbody span");
28217 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
28219 tooltip: this.monthYearText
28222 this.mbtn.on('click', this.showMonthPicker, this);
28223 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
28226 var today = (new Date()).dateFormat(this.format);
28228 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
28229 if (this.showClear) {
28230 baseTb.add( new Roo.Toolbar.Fill());
28233 text: String.format(this.todayText, today),
28234 tooltip: String.format(this.todayTip, today),
28235 handler: this.selectToday,
28239 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
28242 if (this.showClear) {
28244 baseTb.add( new Roo.Toolbar.Fill());
28247 cls: 'x-btn-icon x-btn-clear',
28248 handler: function() {
28250 this.fireEvent("select", this, '');
28260 this.update(this.value);
28263 createMonthPicker : function(){
28264 if(!this.monthPicker.dom.firstChild){
28265 var buf = ['<table border="0" cellspacing="0">'];
28266 for(var i = 0; i < 6; i++){
28268 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
28269 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
28271 '<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>' :
28272 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
28276 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
28278 '</button><button type="button" class="x-date-mp-cancel">',
28280 '</button></td></tr>',
28283 this.monthPicker.update(buf.join(''));
28284 this.monthPicker.on('click', this.onMonthClick, this);
28285 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
28287 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
28288 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
28290 this.mpMonths.each(function(m, a, i){
28293 m.dom.xmonth = 5 + Math.round(i * .5);
28295 m.dom.xmonth = Math.round((i-1) * .5);
28301 showMonthPicker : function(){
28302 this.createMonthPicker();
28303 var size = this.el.getSize();
28304 this.monthPicker.setSize(size);
28305 this.monthPicker.child('table').setSize(size);
28307 this.mpSelMonth = (this.activeDate || this.value).getMonth();
28308 this.updateMPMonth(this.mpSelMonth);
28309 this.mpSelYear = (this.activeDate || this.value).getFullYear();
28310 this.updateMPYear(this.mpSelYear);
28312 this.monthPicker.slideIn('t', {duration:.2});
28315 updateMPYear : function(y){
28317 var ys = this.mpYears.elements;
28318 for(var i = 1; i <= 10; i++){
28319 var td = ys[i-1], y2;
28321 y2 = y + Math.round(i * .5);
28322 td.firstChild.innerHTML = y2;
28325 y2 = y - (5-Math.round(i * .5));
28326 td.firstChild.innerHTML = y2;
28329 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
28333 updateMPMonth : function(sm){
28334 this.mpMonths.each(function(m, a, i){
28335 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
28339 selectMPMonth: function(m){
28343 onMonthClick : function(e, t){
28345 var el = new Roo.Element(t), pn;
28346 if(el.is('button.x-date-mp-cancel')){
28347 this.hideMonthPicker();
28349 else if(el.is('button.x-date-mp-ok')){
28350 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
28351 this.hideMonthPicker();
28353 else if(pn = el.up('td.x-date-mp-month', 2)){
28354 this.mpMonths.removeClass('x-date-mp-sel');
28355 pn.addClass('x-date-mp-sel');
28356 this.mpSelMonth = pn.dom.xmonth;
28358 else if(pn = el.up('td.x-date-mp-year', 2)){
28359 this.mpYears.removeClass('x-date-mp-sel');
28360 pn.addClass('x-date-mp-sel');
28361 this.mpSelYear = pn.dom.xyear;
28363 else if(el.is('a.x-date-mp-prev')){
28364 this.updateMPYear(this.mpyear-10);
28366 else if(el.is('a.x-date-mp-next')){
28367 this.updateMPYear(this.mpyear+10);
28371 onMonthDblClick : function(e, t){
28373 var el = new Roo.Element(t), pn;
28374 if(pn = el.up('td.x-date-mp-month', 2)){
28375 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
28376 this.hideMonthPicker();
28378 else if(pn = el.up('td.x-date-mp-year', 2)){
28379 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
28380 this.hideMonthPicker();
28384 hideMonthPicker : function(disableAnim){
28385 if(this.monthPicker){
28386 if(disableAnim === true){
28387 this.monthPicker.hide();
28389 this.monthPicker.slideOut('t', {duration:.2});
28395 showPrevMonth : function(e){
28396 this.update(this.activeDate.add("mo", -1));
28400 showNextMonth : function(e){
28401 this.update(this.activeDate.add("mo", 1));
28405 showPrevYear : function(){
28406 this.update(this.activeDate.add("y", -1));
28410 showNextYear : function(){
28411 this.update(this.activeDate.add("y", 1));
28415 handleMouseWheel : function(e){
28416 var delta = e.getWheelDelta();
28418 this.showPrevMonth();
28420 } else if(delta < 0){
28421 this.showNextMonth();
28427 handleDateClick : function(e, t){
28429 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
28430 this.setValue(new Date(t.dateValue));
28431 this.fireEvent("select", this, this.value);
28436 selectToday : function(){
28437 this.setValue(new Date().clearTime());
28438 this.fireEvent("select", this, this.value);
28442 update : function(date)
28444 var vd = this.activeDate;
28445 this.activeDate = date;
28447 var t = date.getTime();
28448 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
28449 this.cells.removeClass("x-date-selected");
28450 this.cells.each(function(c){
28451 if(c.dom.firstChild.dateValue == t){
28452 c.addClass("x-date-selected");
28453 setTimeout(function(){
28454 try{c.dom.firstChild.focus();}catch(e){}
28463 var days = date.getDaysInMonth();
28464 var firstOfMonth = date.getFirstDateOfMonth();
28465 var startingPos = firstOfMonth.getDay()-this.startDay;
28467 if(startingPos <= this.startDay){
28471 var pm = date.add("mo", -1);
28472 var prevStart = pm.getDaysInMonth()-startingPos;
28474 var cells = this.cells.elements;
28475 var textEls = this.textNodes;
28476 days += startingPos;
28478 // convert everything to numbers so it's fast
28479 var day = 86400000;
28480 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
28481 var today = new Date().clearTime().getTime();
28482 var sel = date.clearTime().getTime();
28483 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
28484 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
28485 var ddMatch = this.disabledDatesRE;
28486 var ddText = this.disabledDatesText;
28487 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
28488 var ddaysText = this.disabledDaysText;
28489 var format = this.format;
28491 var setCellClass = function(cal, cell){
28493 var t = d.getTime();
28494 cell.firstChild.dateValue = t;
28496 cell.className += " x-date-today";
28497 cell.title = cal.todayText;
28500 cell.className += " x-date-selected";
28501 setTimeout(function(){
28502 try{cell.firstChild.focus();}catch(e){}
28507 cell.className = " x-date-disabled";
28508 cell.title = cal.minText;
28512 cell.className = " x-date-disabled";
28513 cell.title = cal.maxText;
28517 if(ddays.indexOf(d.getDay()) != -1){
28518 cell.title = ddaysText;
28519 cell.className = " x-date-disabled";
28522 if(ddMatch && format){
28523 var fvalue = d.dateFormat(format);
28524 if(ddMatch.test(fvalue)){
28525 cell.title = ddText.replace("%0", fvalue);
28526 cell.className = " x-date-disabled";
28532 for(; i < startingPos; i++) {
28533 textEls[i].innerHTML = (++prevStart);
28534 d.setDate(d.getDate()+1);
28535 cells[i].className = "x-date-prevday";
28536 setCellClass(this, cells[i]);
28538 for(; i < days; i++){
28539 intDay = i - startingPos + 1;
28540 textEls[i].innerHTML = (intDay);
28541 d.setDate(d.getDate()+1);
28542 cells[i].className = "x-date-active";
28543 setCellClass(this, cells[i]);
28546 for(; i < 42; i++) {
28547 textEls[i].innerHTML = (++extraDays);
28548 d.setDate(d.getDate()+1);
28549 cells[i].className = "x-date-nextday";
28550 setCellClass(this, cells[i]);
28553 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
28554 this.fireEvent('monthchange', this, date);
28556 if(!this.internalRender){
28557 var main = this.el.dom.firstChild;
28558 var w = main.offsetWidth;
28559 this.el.setWidth(w + this.el.getBorderWidth("lr"));
28560 Roo.fly(main).setWidth(w);
28561 this.internalRender = true;
28562 // opera does not respect the auto grow header center column
28563 // then, after it gets a width opera refuses to recalculate
28564 // without a second pass
28565 if(Roo.isOpera && !this.secondPass){
28566 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
28567 this.secondPass = true;
28568 this.update.defer(10, this, [date]);
28576 * Ext JS Library 1.1.1
28577 * Copyright(c) 2006-2007, Ext JS, LLC.
28579 * Originally Released Under LGPL - original licence link has changed is not relivant.
28582 * <script type="text/javascript">
28585 * @class Roo.TabPanel
28586 * @extends Roo.util.Observable
28587 * A lightweight tab container.
28591 // basic tabs 1, built from existing content
28592 var tabs = new Roo.TabPanel("tabs1");
28593 tabs.addTab("script", "View Script");
28594 tabs.addTab("markup", "View Markup");
28595 tabs.activate("script");
28597 // more advanced tabs, built from javascript
28598 var jtabs = new Roo.TabPanel("jtabs");
28599 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
28601 // set up the UpdateManager
28602 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
28603 var updater = tab2.getUpdateManager();
28604 updater.setDefaultUrl("ajax1.htm");
28605 tab2.on('activate', updater.refresh, updater, true);
28607 // Use setUrl for Ajax loading
28608 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
28609 tab3.setUrl("ajax2.htm", null, true);
28612 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
28615 jtabs.activate("jtabs-1");
28618 * Create a new TabPanel.
28619 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
28620 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
28622 Roo.TabPanel = function(container, config){
28624 * The container element for this TabPanel.
28625 * @type Roo.Element
28627 this.el = Roo.get(container, true);
28629 if(typeof config == "boolean"){
28630 this.tabPosition = config ? "bottom" : "top";
28632 Roo.apply(this, config);
28635 if(this.tabPosition == "bottom"){
28636 this.bodyEl = Roo.get(this.createBody(this.el.dom));
28637 this.el.addClass("x-tabs-bottom");
28639 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
28640 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
28641 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
28643 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
28645 if(this.tabPosition != "bottom"){
28646 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
28647 * @type Roo.Element
28649 this.bodyEl = Roo.get(this.createBody(this.el.dom));
28650 this.el.addClass("x-tabs-top");
28654 this.bodyEl.setStyle("position", "relative");
28656 this.active = null;
28657 this.activateDelegate = this.activate.createDelegate(this);
28662 * Fires when the active tab changes
28663 * @param {Roo.TabPanel} this
28664 * @param {Roo.TabPanelItem} activePanel The new active tab
28668 * @event beforetabchange
28669 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
28670 * @param {Roo.TabPanel} this
28671 * @param {Object} e Set cancel to true on this object to cancel the tab change
28672 * @param {Roo.TabPanelItem} tab The tab being changed to
28674 "beforetabchange" : true
28677 Roo.EventManager.onWindowResize(this.onResize, this);
28678 this.cpad = this.el.getPadding("lr");
28679 this.hiddenCount = 0;
28682 // toolbar on the tabbar support...
28683 if (this.toolbar) {
28684 var tcfg = this.toolbar;
28685 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
28686 this.toolbar = new Roo.Toolbar(tcfg);
28687 if (Roo.isSafari) {
28688 var tbl = tcfg.container.child('table', true);
28689 tbl.setAttribute('width', '100%');
28696 Roo.TabPanel.superclass.constructor.call(this);
28699 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
28701 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
28703 tabPosition : "top",
28705 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
28707 currentTabWidth : 0,
28709 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
28713 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
28717 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
28719 preferredTabWidth : 175,
28721 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
28723 resizeTabs : false,
28725 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
28727 monitorResize : true,
28729 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
28734 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
28735 * @param {String} id The id of the div to use <b>or create</b>
28736 * @param {String} text The text for the tab
28737 * @param {String} content (optional) Content to put in the TabPanelItem body
28738 * @param {Boolean} closable (optional) True to create a close icon on the tab
28739 * @return {Roo.TabPanelItem} The created TabPanelItem
28741 addTab : function(id, text, content, closable){
28742 var item = new Roo.TabPanelItem(this, id, text, closable);
28743 this.addTabItem(item);
28745 item.setContent(content);
28751 * Returns the {@link Roo.TabPanelItem} with the specified id/index
28752 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
28753 * @return {Roo.TabPanelItem}
28755 getTab : function(id){
28756 return this.items[id];
28760 * Hides the {@link Roo.TabPanelItem} with the specified id/index
28761 * @param {String/Number} id The id or index of the TabPanelItem to hide.
28763 hideTab : function(id){
28764 var t = this.items[id];
28767 this.hiddenCount++;
28768 this.autoSizeTabs();
28773 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
28774 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
28776 unhideTab : function(id){
28777 var t = this.items[id];
28779 t.setHidden(false);
28780 this.hiddenCount--;
28781 this.autoSizeTabs();
28786 * Adds an existing {@link Roo.TabPanelItem}.
28787 * @param {Roo.TabPanelItem} item The TabPanelItem to add
28789 addTabItem : function(item){
28790 this.items[item.id] = item;
28791 this.items.push(item);
28792 if(this.resizeTabs){
28793 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
28794 this.autoSizeTabs();
28801 * Removes a {@link Roo.TabPanelItem}.
28802 * @param {String/Number} id The id or index of the TabPanelItem to remove.
28804 removeTab : function(id){
28805 var items = this.items;
28806 var tab = items[id];
28807 if(!tab) { return; }
28808 var index = items.indexOf(tab);
28809 if(this.active == tab && items.length > 1){
28810 var newTab = this.getNextAvailable(index);
28815 this.stripEl.dom.removeChild(tab.pnode.dom);
28816 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
28817 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
28819 items.splice(index, 1);
28820 delete this.items[tab.id];
28821 tab.fireEvent("close", tab);
28822 tab.purgeListeners();
28823 this.autoSizeTabs();
28826 getNextAvailable : function(start){
28827 var items = this.items;
28829 // look for a next tab that will slide over to
28830 // replace the one being removed
28831 while(index < items.length){
28832 var item = items[++index];
28833 if(item && !item.isHidden()){
28837 // if one isn't found select the previous tab (on the left)
28840 var item = items[--index];
28841 if(item && !item.isHidden()){
28849 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
28850 * @param {String/Number} id The id or index of the TabPanelItem to disable.
28852 disableTab : function(id){
28853 var tab = this.items[id];
28854 if(tab && this.active != tab){
28860 * Enables a {@link Roo.TabPanelItem} that is disabled.
28861 * @param {String/Number} id The id or index of the TabPanelItem to enable.
28863 enableTab : function(id){
28864 var tab = this.items[id];
28869 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
28870 * @param {String/Number} id The id or index of the TabPanelItem to activate.
28871 * @return {Roo.TabPanelItem} The TabPanelItem.
28873 activate : function(id){
28874 var tab = this.items[id];
28878 if(tab == this.active || tab.disabled){
28882 this.fireEvent("beforetabchange", this, e, tab);
28883 if(e.cancel !== true && !tab.disabled){
28885 this.active.hide();
28887 this.active = this.items[id];
28888 this.active.show();
28889 this.fireEvent("tabchange", this, this.active);
28895 * Gets the active {@link Roo.TabPanelItem}.
28896 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
28898 getActiveTab : function(){
28899 return this.active;
28903 * Updates the tab body element to fit the height of the container element
28904 * for overflow scrolling
28905 * @param {Number} targetHeight (optional) Override the starting height from the elements height
28907 syncHeight : function(targetHeight){
28908 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
28909 var bm = this.bodyEl.getMargins();
28910 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
28911 this.bodyEl.setHeight(newHeight);
28915 onResize : function(){
28916 if(this.monitorResize){
28917 this.autoSizeTabs();
28922 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
28924 beginUpdate : function(){
28925 this.updating = true;
28929 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
28931 endUpdate : function(){
28932 this.updating = false;
28933 this.autoSizeTabs();
28937 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
28939 autoSizeTabs : function(){
28940 var count = this.items.length;
28941 var vcount = count - this.hiddenCount;
28942 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
28945 var w = Math.max(this.el.getWidth() - this.cpad, 10);
28946 var availWidth = Math.floor(w / vcount);
28947 var b = this.stripBody;
28948 if(b.getWidth() > w){
28949 var tabs = this.items;
28950 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
28951 if(availWidth < this.minTabWidth){
28952 /*if(!this.sleft){ // incomplete scrolling code
28953 this.createScrollButtons();
28956 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
28959 if(this.currentTabWidth < this.preferredTabWidth){
28960 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
28966 * Returns the number of tabs in this TabPanel.
28969 getCount : function(){
28970 return this.items.length;
28974 * Resizes all the tabs to the passed width
28975 * @param {Number} The new width
28977 setTabWidth : function(width){
28978 this.currentTabWidth = width;
28979 for(var i = 0, len = this.items.length; i < len; i++) {
28980 if(!this.items[i].isHidden()) {
28981 this.items[i].setWidth(width);
28987 * Destroys this TabPanel
28988 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
28990 destroy : function(removeEl){
28991 Roo.EventManager.removeResizeListener(this.onResize, this);
28992 for(var i = 0, len = this.items.length; i < len; i++){
28993 this.items[i].purgeListeners();
28995 if(removeEl === true){
28996 this.el.update("");
29003 * @class Roo.TabPanelItem
29004 * @extends Roo.util.Observable
29005 * Represents an individual item (tab plus body) in a TabPanel.
29006 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
29007 * @param {String} id The id of this TabPanelItem
29008 * @param {String} text The text for the tab of this TabPanelItem
29009 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
29011 Roo.TabPanelItem = function(tabPanel, id, text, closable){
29013 * The {@link Roo.TabPanel} this TabPanelItem belongs to
29014 * @type Roo.TabPanel
29016 this.tabPanel = tabPanel;
29018 * The id for this TabPanelItem
29023 this.disabled = false;
29027 this.loaded = false;
29028 this.closable = closable;
29031 * The body element for this TabPanelItem.
29032 * @type Roo.Element
29034 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
29035 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
29036 this.bodyEl.setStyle("display", "block");
29037 this.bodyEl.setStyle("zoom", "1");
29040 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
29042 this.el = Roo.get(els.el, true);
29043 this.inner = Roo.get(els.inner, true);
29044 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
29045 this.pnode = Roo.get(els.el.parentNode, true);
29046 this.el.on("mousedown", this.onTabMouseDown, this);
29047 this.el.on("click", this.onTabClick, this);
29050 var c = Roo.get(els.close, true);
29051 c.dom.title = this.closeText;
29052 c.addClassOnOver("close-over");
29053 c.on("click", this.closeClick, this);
29059 * Fires when this tab becomes the active tab.
29060 * @param {Roo.TabPanel} tabPanel The parent TabPanel
29061 * @param {Roo.TabPanelItem} this
29065 * @event beforeclose
29066 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
29067 * @param {Roo.TabPanelItem} this
29068 * @param {Object} e Set cancel to true on this object to cancel the close.
29070 "beforeclose": true,
29073 * Fires when this tab is closed.
29074 * @param {Roo.TabPanelItem} this
29078 * @event deactivate
29079 * Fires when this tab is no longer the active tab.
29080 * @param {Roo.TabPanel} tabPanel The parent TabPanel
29081 * @param {Roo.TabPanelItem} this
29083 "deactivate" : true
29085 this.hidden = false;
29087 Roo.TabPanelItem.superclass.constructor.call(this);
29090 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
29091 purgeListeners : function(){
29092 Roo.util.Observable.prototype.purgeListeners.call(this);
29093 this.el.removeAllListeners();
29096 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
29099 this.pnode.addClass("on");
29102 this.tabPanel.stripWrap.repaint();
29104 this.fireEvent("activate", this.tabPanel, this);
29108 * Returns true if this tab is the active tab.
29109 * @return {Boolean}
29111 isActive : function(){
29112 return this.tabPanel.getActiveTab() == this;
29116 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
29119 this.pnode.removeClass("on");
29121 this.fireEvent("deactivate", this.tabPanel, this);
29124 hideAction : function(){
29125 this.bodyEl.hide();
29126 this.bodyEl.setStyle("position", "absolute");
29127 this.bodyEl.setLeft("-20000px");
29128 this.bodyEl.setTop("-20000px");
29131 showAction : function(){
29132 this.bodyEl.setStyle("position", "relative");
29133 this.bodyEl.setTop("");
29134 this.bodyEl.setLeft("");
29135 this.bodyEl.show();
29139 * Set the tooltip for the tab.
29140 * @param {String} tooltip The tab's tooltip
29142 setTooltip : function(text){
29143 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
29144 this.textEl.dom.qtip = text;
29145 this.textEl.dom.removeAttribute('title');
29147 this.textEl.dom.title = text;
29151 onTabClick : function(e){
29152 e.preventDefault();
29153 this.tabPanel.activate(this.id);
29156 onTabMouseDown : function(e){
29157 e.preventDefault();
29158 this.tabPanel.activate(this.id);
29161 getWidth : function(){
29162 return this.inner.getWidth();
29165 setWidth : function(width){
29166 var iwidth = width - this.pnode.getPadding("lr");
29167 this.inner.setWidth(iwidth);
29168 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
29169 this.pnode.setWidth(width);
29173 * Show or hide the tab
29174 * @param {Boolean} hidden True to hide or false to show.
29176 setHidden : function(hidden){
29177 this.hidden = hidden;
29178 this.pnode.setStyle("display", hidden ? "none" : "");
29182 * Returns true if this tab is "hidden"
29183 * @return {Boolean}
29185 isHidden : function(){
29186 return this.hidden;
29190 * Returns the text for this tab
29193 getText : function(){
29197 autoSize : function(){
29198 //this.el.beginMeasure();
29199 this.textEl.setWidth(1);
29201 * #2804 [new] Tabs in Roojs
29202 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
29204 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
29205 //this.el.endMeasure();
29209 * Sets the text for the tab (Note: this also sets the tooltip text)
29210 * @param {String} text The tab's text and tooltip
29212 setText : function(text){
29214 this.textEl.update(text);
29215 this.setTooltip(text);
29216 if(!this.tabPanel.resizeTabs){
29221 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
29223 activate : function(){
29224 this.tabPanel.activate(this.id);
29228 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
29230 disable : function(){
29231 if(this.tabPanel.active != this){
29232 this.disabled = true;
29233 this.pnode.addClass("disabled");
29238 * Enables this TabPanelItem if it was previously disabled.
29240 enable : function(){
29241 this.disabled = false;
29242 this.pnode.removeClass("disabled");
29246 * Sets the content for this TabPanelItem.
29247 * @param {String} content The content
29248 * @param {Boolean} loadScripts true to look for and load scripts
29250 setContent : function(content, loadScripts){
29251 this.bodyEl.update(content, loadScripts);
29255 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
29256 * @return {Roo.UpdateManager} The UpdateManager
29258 getUpdateManager : function(){
29259 return this.bodyEl.getUpdateManager();
29263 * Set a URL to be used to load the content for this TabPanelItem.
29264 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
29265 * @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)
29266 * @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)
29267 * @return {Roo.UpdateManager} The UpdateManager
29269 setUrl : function(url, params, loadOnce){
29270 if(this.refreshDelegate){
29271 this.un('activate', this.refreshDelegate);
29273 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
29274 this.on("activate", this.refreshDelegate);
29275 return this.bodyEl.getUpdateManager();
29279 _handleRefresh : function(url, params, loadOnce){
29280 if(!loadOnce || !this.loaded){
29281 var updater = this.bodyEl.getUpdateManager();
29282 updater.update(url, params, this._setLoaded.createDelegate(this));
29287 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
29288 * Will fail silently if the setUrl method has not been called.
29289 * This does not activate the panel, just updates its content.
29291 refresh : function(){
29292 if(this.refreshDelegate){
29293 this.loaded = false;
29294 this.refreshDelegate();
29299 _setLoaded : function(){
29300 this.loaded = true;
29304 closeClick : function(e){
29307 this.fireEvent("beforeclose", this, o);
29308 if(o.cancel !== true){
29309 this.tabPanel.removeTab(this.id);
29313 * The text displayed in the tooltip for the close icon.
29316 closeText : "Close this tab"
29320 Roo.TabPanel.prototype.createStrip = function(container){
29321 var strip = document.createElement("div");
29322 strip.className = "x-tabs-wrap";
29323 container.appendChild(strip);
29327 Roo.TabPanel.prototype.createStripList = function(strip){
29328 // div wrapper for retard IE
29329 // returns the "tr" element.
29330 strip.innerHTML = '<div class="x-tabs-strip-wrap">'+
29331 '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
29332 '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
29333 return strip.firstChild.firstChild.firstChild.firstChild;
29336 Roo.TabPanel.prototype.createBody = function(container){
29337 var body = document.createElement("div");
29338 Roo.id(body, "tab-body");
29339 Roo.fly(body).addClass("x-tabs-body");
29340 container.appendChild(body);
29344 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
29345 var body = Roo.getDom(id);
29347 body = document.createElement("div");
29350 Roo.fly(body).addClass("x-tabs-item-body");
29351 bodyEl.insertBefore(body, bodyEl.firstChild);
29355 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
29356 var td = document.createElement("td");
29357 stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
29358 //stripEl.appendChild(td);
29360 td.className = "x-tabs-closable";
29361 if(!this.closeTpl){
29362 this.closeTpl = new Roo.Template(
29363 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
29364 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
29365 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
29368 var el = this.closeTpl.overwrite(td, {"text": text});
29369 var close = el.getElementsByTagName("div")[0];
29370 var inner = el.getElementsByTagName("em")[0];
29371 return {"el": el, "close": close, "inner": inner};
29374 this.tabTpl = new Roo.Template(
29375 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
29376 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
29379 var el = this.tabTpl.overwrite(td, {"text": text});
29380 var inner = el.getElementsByTagName("em")[0];
29381 return {"el": el, "inner": inner};
29385 * Ext JS Library 1.1.1
29386 * Copyright(c) 2006-2007, Ext JS, LLC.
29388 * Originally Released Under LGPL - original licence link has changed is not relivant.
29391 * <script type="text/javascript">
29395 * @class Roo.Button
29396 * @extends Roo.util.Observable
29397 * Simple Button class
29398 * @cfg {String} text The button text
29399 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
29400 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
29401 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
29402 * @cfg {Object} scope The scope of the handler
29403 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
29404 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
29405 * @cfg {Boolean} hidden True to start hidden (defaults to false)
29406 * @cfg {Boolean} disabled True to start disabled (defaults to false)
29407 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
29408 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
29409 applies if enableToggle = true)
29410 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
29411 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
29412 an {@link Roo.util.ClickRepeater} config object (defaults to false).
29414 * Create a new button
29415 * @param {Object} config The config object
29417 Roo.Button = function(renderTo, config)
29421 renderTo = config.renderTo || false;
29424 Roo.apply(this, config);
29428 * Fires when this button is clicked
29429 * @param {Button} this
29430 * @param {EventObject} e The click event
29435 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
29436 * @param {Button} this
29437 * @param {Boolean} pressed
29442 * Fires when the mouse hovers over the button
29443 * @param {Button} this
29444 * @param {Event} e The event object
29446 'mouseover' : true,
29449 * Fires when the mouse exits the button
29450 * @param {Button} this
29451 * @param {Event} e The event object
29456 * Fires when the button is rendered
29457 * @param {Button} this
29462 this.menu = Roo.menu.MenuMgr.get(this.menu);
29464 // register listeners first!! - so render can be captured..
29465 Roo.util.Observable.call(this);
29467 this.render(renderTo);
29473 Roo.extend(Roo.Button, Roo.util.Observable, {
29479 * Read-only. True if this button is hidden
29484 * Read-only. True if this button is disabled
29489 * Read-only. True if this button is pressed (only if enableToggle = true)
29495 * @cfg {Number} tabIndex
29496 * The DOM tabIndex for this button (defaults to undefined)
29498 tabIndex : undefined,
29501 * @cfg {Boolean} enableToggle
29502 * True to enable pressed/not pressed toggling (defaults to false)
29504 enableToggle: false,
29506 * @cfg {Mixed} menu
29507 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
29511 * @cfg {String} menuAlign
29512 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
29514 menuAlign : "tl-bl?",
29517 * @cfg {String} iconCls
29518 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
29520 iconCls : undefined,
29522 * @cfg {String} type
29523 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
29528 menuClassTarget: 'tr',
29531 * @cfg {String} clickEvent
29532 * The type of event to map to the button's event handler (defaults to 'click')
29534 clickEvent : 'click',
29537 * @cfg {Boolean} handleMouseEvents
29538 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
29540 handleMouseEvents : true,
29543 * @cfg {String} tooltipType
29544 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
29546 tooltipType : 'qtip',
29549 * @cfg {String} cls
29550 * A CSS class to apply to the button's main element.
29554 * @cfg {Roo.Template} template (Optional)
29555 * An {@link Roo.Template} with which to create the Button's main element. This Template must
29556 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
29557 * require code modifications if required elements (e.g. a button) aren't present.
29561 render : function(renderTo){
29563 if(this.hideParent){
29564 this.parentEl = Roo.get(renderTo);
29566 if(!this.dhconfig){
29567 if(!this.template){
29568 if(!Roo.Button.buttonTemplate){
29569 // hideous table template
29570 Roo.Button.buttonTemplate = new Roo.Template(
29571 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
29572 '<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>',
29573 "</tr></tbody></table>");
29575 this.template = Roo.Button.buttonTemplate;
29577 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
29578 var btnEl = btn.child("button:first");
29579 btnEl.on('focus', this.onFocus, this);
29580 btnEl.on('blur', this.onBlur, this);
29582 btn.addClass(this.cls);
29585 btnEl.setStyle('background-image', 'url(' +this.icon +')');
29588 btnEl.addClass(this.iconCls);
29590 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
29593 if(this.tabIndex !== undefined){
29594 btnEl.dom.tabIndex = this.tabIndex;
29597 if(typeof this.tooltip == 'object'){
29598 Roo.QuickTips.tips(Roo.apply({
29602 btnEl.dom[this.tooltipType] = this.tooltip;
29606 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
29610 this.el.dom.id = this.el.id = this.id;
29613 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
29614 this.menu.on("show", this.onMenuShow, this);
29615 this.menu.on("hide", this.onMenuHide, this);
29617 btn.addClass("x-btn");
29618 if(Roo.isIE && !Roo.isIE7){
29619 this.autoWidth.defer(1, this);
29623 if(this.handleMouseEvents){
29624 btn.on("mouseover", this.onMouseOver, this);
29625 btn.on("mouseout", this.onMouseOut, this);
29626 btn.on("mousedown", this.onMouseDown, this);
29628 btn.on(this.clickEvent, this.onClick, this);
29629 //btn.on("mouseup", this.onMouseUp, this);
29636 Roo.ButtonToggleMgr.register(this);
29638 this.el.addClass("x-btn-pressed");
29641 var repeater = new Roo.util.ClickRepeater(btn,
29642 typeof this.repeat == "object" ? this.repeat : {}
29644 repeater.on("click", this.onClick, this);
29647 this.fireEvent('render', this);
29651 * Returns the button's underlying element
29652 * @return {Roo.Element} The element
29654 getEl : function(){
29659 * Destroys this Button and removes any listeners.
29661 destroy : function(){
29662 Roo.ButtonToggleMgr.unregister(this);
29663 this.el.removeAllListeners();
29664 this.purgeListeners();
29669 autoWidth : function(){
29671 this.el.setWidth("auto");
29672 if(Roo.isIE7 && Roo.isStrict){
29673 var ib = this.el.child('button');
29674 if(ib && ib.getWidth() > 20){
29676 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
29681 this.el.beginMeasure();
29683 if(this.el.getWidth() < this.minWidth){
29684 this.el.setWidth(this.minWidth);
29687 this.el.endMeasure();
29694 * Assigns this button's click handler
29695 * @param {Function} handler The function to call when the button is clicked
29696 * @param {Object} scope (optional) Scope for the function passed in
29698 setHandler : function(handler, scope){
29699 this.handler = handler;
29700 this.scope = scope;
29704 * Sets this button's text
29705 * @param {String} text The button text
29707 setText : function(text){
29710 this.el.child("td.x-btn-center button.x-btn-text").update(text);
29716 * Gets the text for this button
29717 * @return {String} The button text
29719 getText : function(){
29727 this.hidden = false;
29729 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
29737 this.hidden = true;
29739 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
29744 * Convenience function for boolean show/hide
29745 * @param {Boolean} visible True to show, false to hide
29747 setVisible: function(visible){
29756 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
29757 * @param {Boolean} state (optional) Force a particular state
29759 toggle : function(state){
29760 state = state === undefined ? !this.pressed : state;
29761 if(state != this.pressed){
29763 this.el.addClass("x-btn-pressed");
29764 this.pressed = true;
29765 this.fireEvent("toggle", this, true);
29767 this.el.removeClass("x-btn-pressed");
29768 this.pressed = false;
29769 this.fireEvent("toggle", this, false);
29771 if(this.toggleHandler){
29772 this.toggleHandler.call(this.scope || this, this, state);
29780 focus : function(){
29781 this.el.child('button:first').focus();
29785 * Disable this button
29787 disable : function(){
29789 this.el.addClass("x-btn-disabled");
29791 this.disabled = true;
29795 * Enable this button
29797 enable : function(){
29799 this.el.removeClass("x-btn-disabled");
29801 this.disabled = false;
29805 * Convenience function for boolean enable/disable
29806 * @param {Boolean} enabled True to enable, false to disable
29808 setDisabled : function(v){
29809 this[v !== true ? "enable" : "disable"]();
29813 onClick : function(e)
29816 e.preventDefault();
29821 if(!this.disabled){
29822 if(this.enableToggle){
29825 if(this.menu && !this.menu.isVisible()){
29826 this.menu.show(this.el, this.menuAlign);
29828 this.fireEvent("click", this, e);
29830 this.el.removeClass("x-btn-over");
29831 this.handler.call(this.scope || this, this, e);
29836 onMouseOver : function(e){
29837 if(!this.disabled){
29838 this.el.addClass("x-btn-over");
29839 this.fireEvent('mouseover', this, e);
29843 onMouseOut : function(e){
29844 if(!e.within(this.el, true)){
29845 this.el.removeClass("x-btn-over");
29846 this.fireEvent('mouseout', this, e);
29850 onFocus : function(e){
29851 if(!this.disabled){
29852 this.el.addClass("x-btn-focus");
29856 onBlur : function(e){
29857 this.el.removeClass("x-btn-focus");
29860 onMouseDown : function(e){
29861 if(!this.disabled && e.button == 0){
29862 this.el.addClass("x-btn-click");
29863 Roo.get(document).on('mouseup', this.onMouseUp, this);
29867 onMouseUp : function(e){
29869 this.el.removeClass("x-btn-click");
29870 Roo.get(document).un('mouseup', this.onMouseUp, this);
29874 onMenuShow : function(e){
29875 this.el.addClass("x-btn-menu-active");
29878 onMenuHide : function(e){
29879 this.el.removeClass("x-btn-menu-active");
29883 // Private utility class used by Button
29884 Roo.ButtonToggleMgr = function(){
29887 function toggleGroup(btn, state){
29889 var g = groups[btn.toggleGroup];
29890 for(var i = 0, l = g.length; i < l; i++){
29892 g[i].toggle(false);
29899 register : function(btn){
29900 if(!btn.toggleGroup){
29903 var g = groups[btn.toggleGroup];
29905 g = groups[btn.toggleGroup] = [];
29908 btn.on("toggle", toggleGroup);
29911 unregister : function(btn){
29912 if(!btn.toggleGroup){
29915 var g = groups[btn.toggleGroup];
29918 btn.un("toggle", toggleGroup);
29924 * Ext JS Library 1.1.1
29925 * Copyright(c) 2006-2007, Ext JS, LLC.
29927 * Originally Released Under LGPL - original licence link has changed is not relivant.
29930 * <script type="text/javascript">
29934 * @class Roo.SplitButton
29935 * @extends Roo.Button
29936 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
29937 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
29938 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
29939 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
29940 * @cfg {String} arrowTooltip The title attribute of the arrow
29942 * Create a new menu button
29943 * @param {String/HTMLElement/Element} renderTo The element to append the button to
29944 * @param {Object} config The config object
29946 Roo.SplitButton = function(renderTo, config){
29947 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
29949 * @event arrowclick
29950 * Fires when this button's arrow is clicked
29951 * @param {SplitButton} this
29952 * @param {EventObject} e The click event
29954 this.addEvents({"arrowclick":true});
29957 Roo.extend(Roo.SplitButton, Roo.Button, {
29958 render : function(renderTo){
29959 // this is one sweet looking template!
29960 var tpl = new Roo.Template(
29961 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
29962 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
29963 '<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>',
29964 "</tbody></table></td><td>",
29965 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
29966 '<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>',
29967 "</tbody></table></td></tr></table>"
29969 var btn = tpl.append(renderTo, [this.text, this.type], true);
29970 var btnEl = btn.child("button");
29972 btn.addClass(this.cls);
29975 btnEl.setStyle('background-image', 'url(' +this.icon +')');
29978 btnEl.addClass(this.iconCls);
29980 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
29984 if(this.handleMouseEvents){
29985 btn.on("mouseover", this.onMouseOver, this);
29986 btn.on("mouseout", this.onMouseOut, this);
29987 btn.on("mousedown", this.onMouseDown, this);
29988 btn.on("mouseup", this.onMouseUp, this);
29990 btn.on(this.clickEvent, this.onClick, this);
29992 if(typeof this.tooltip == 'object'){
29993 Roo.QuickTips.tips(Roo.apply({
29997 btnEl.dom[this.tooltipType] = this.tooltip;
30000 if(this.arrowTooltip){
30001 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
30010 this.el.addClass("x-btn-pressed");
30012 if(Roo.isIE && !Roo.isIE7){
30013 this.autoWidth.defer(1, this);
30018 this.menu.on("show", this.onMenuShow, this);
30019 this.menu.on("hide", this.onMenuHide, this);
30021 this.fireEvent('render', this);
30025 autoWidth : function(){
30027 var tbl = this.el.child("table:first");
30028 var tbl2 = this.el.child("table:last");
30029 this.el.setWidth("auto");
30030 tbl.setWidth("auto");
30031 if(Roo.isIE7 && Roo.isStrict){
30032 var ib = this.el.child('button:first');
30033 if(ib && ib.getWidth() > 20){
30035 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
30040 this.el.beginMeasure();
30042 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
30043 tbl.setWidth(this.minWidth-tbl2.getWidth());
30046 this.el.endMeasure();
30049 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
30053 * Sets this button's click handler
30054 * @param {Function} handler The function to call when the button is clicked
30055 * @param {Object} scope (optional) Scope for the function passed above
30057 setHandler : function(handler, scope){
30058 this.handler = handler;
30059 this.scope = scope;
30063 * Sets this button's arrow click handler
30064 * @param {Function} handler The function to call when the arrow is clicked
30065 * @param {Object} scope (optional) Scope for the function passed above
30067 setArrowHandler : function(handler, scope){
30068 this.arrowHandler = handler;
30069 this.scope = scope;
30075 focus : function(){
30077 this.el.child("button:first").focus();
30082 onClick : function(e){
30083 e.preventDefault();
30084 if(!this.disabled){
30085 if(e.getTarget(".x-btn-menu-arrow-wrap")){
30086 if(this.menu && !this.menu.isVisible()){
30087 this.menu.show(this.el, this.menuAlign);
30089 this.fireEvent("arrowclick", this, e);
30090 if(this.arrowHandler){
30091 this.arrowHandler.call(this.scope || this, this, e);
30094 this.fireEvent("click", this, e);
30096 this.handler.call(this.scope || this, this, e);
30102 onMouseDown : function(e){
30103 if(!this.disabled){
30104 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
30108 onMouseUp : function(e){
30109 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
30114 // backwards compat
30115 Roo.MenuButton = Roo.SplitButton;/*
30117 * Ext JS Library 1.1.1
30118 * Copyright(c) 2006-2007, Ext JS, LLC.
30120 * Originally Released Under LGPL - original licence link has changed is not relivant.
30123 * <script type="text/javascript">
30127 * @class Roo.Toolbar
30128 * Basic Toolbar class.
30130 * Creates a new Toolbar
30131 * @param {Object} container The config object
30133 Roo.Toolbar = function(container, buttons, config)
30135 /// old consturctor format still supported..
30136 if(container instanceof Array){ // omit the container for later rendering
30137 buttons = container;
30141 if (typeof(container) == 'object' && container.xtype) {
30142 config = container;
30143 container = config.container;
30144 buttons = config.buttons || []; // not really - use items!!
30147 if (config && config.items) {
30148 xitems = config.items;
30149 delete config.items;
30151 Roo.apply(this, config);
30152 this.buttons = buttons;
30155 this.render(container);
30157 this.xitems = xitems;
30158 Roo.each(xitems, function(b) {
30164 Roo.Toolbar.prototype = {
30166 * @cfg {Array} items
30167 * array of button configs or elements to add (will be converted to a MixedCollection)
30171 * @cfg {String/HTMLElement/Element} container
30172 * The id or element that will contain the toolbar
30175 render : function(ct){
30176 this.el = Roo.get(ct);
30178 this.el.addClass(this.cls);
30180 // using a table allows for vertical alignment
30181 // 100% width is needed by Safari...
30182 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
30183 this.tr = this.el.child("tr", true);
30185 this.items = new Roo.util.MixedCollection(false, function(o){
30186 return o.id || ("item" + (++autoId));
30189 this.add.apply(this, this.buttons);
30190 delete this.buttons;
30195 * Adds element(s) to the toolbar -- this function takes a variable number of
30196 * arguments of mixed type and adds them to the toolbar.
30197 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
30199 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
30200 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
30201 * <li>Field: Any form field (equivalent to {@link #addField})</li>
30202 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
30203 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
30204 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
30205 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
30206 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
30207 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
30209 * @param {Mixed} arg2
30210 * @param {Mixed} etc.
30213 var a = arguments, l = a.length;
30214 for(var i = 0; i < l; i++){
30219 _add : function(el) {
30222 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
30225 if (el.applyTo){ // some kind of form field
30226 return this.addField(el);
30228 if (el.render){ // some kind of Toolbar.Item
30229 return this.addItem(el);
30231 if (typeof el == "string"){ // string
30232 if(el == "separator" || el == "-"){
30233 return this.addSeparator();
30236 return this.addSpacer();
30239 return this.addFill();
30241 return this.addText(el);
30244 if(el.tagName){ // element
30245 return this.addElement(el);
30247 if(typeof el == "object"){ // must be button config?
30248 return this.addButton(el);
30250 // and now what?!?!
30256 * Add an Xtype element
30257 * @param {Object} xtype Xtype Object
30258 * @return {Object} created Object
30260 addxtype : function(e){
30261 return this.add(e);
30265 * Returns the Element for this toolbar.
30266 * @return {Roo.Element}
30268 getEl : function(){
30274 * @return {Roo.Toolbar.Item} The separator item
30276 addSeparator : function(){
30277 return this.addItem(new Roo.Toolbar.Separator());
30281 * Adds a spacer element
30282 * @return {Roo.Toolbar.Spacer} The spacer item
30284 addSpacer : function(){
30285 return this.addItem(new Roo.Toolbar.Spacer());
30289 * Adds a fill element that forces subsequent additions to the right side of the toolbar
30290 * @return {Roo.Toolbar.Fill} The fill item
30292 addFill : function(){
30293 return this.addItem(new Roo.Toolbar.Fill());
30297 * Adds any standard HTML element to the toolbar
30298 * @param {String/HTMLElement/Element} el The element or id of the element to add
30299 * @return {Roo.Toolbar.Item} The element's item
30301 addElement : function(el){
30302 return this.addItem(new Roo.Toolbar.Item(el));
30305 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
30306 * @type Roo.util.MixedCollection
30311 * Adds any Toolbar.Item or subclass
30312 * @param {Roo.Toolbar.Item} item
30313 * @return {Roo.Toolbar.Item} The item
30315 addItem : function(item){
30316 var td = this.nextBlock();
30318 this.items.add(item);
30323 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
30324 * @param {Object/Array} config A button config or array of configs
30325 * @return {Roo.Toolbar.Button/Array}
30327 addButton : function(config){
30328 if(config instanceof Array){
30330 for(var i = 0, len = config.length; i < len; i++) {
30331 buttons.push(this.addButton(config[i]));
30336 if(!(config instanceof Roo.Toolbar.Button)){
30338 new Roo.Toolbar.SplitButton(config) :
30339 new Roo.Toolbar.Button(config);
30341 var td = this.nextBlock();
30348 * Adds text to the toolbar
30349 * @param {String} text The text to add
30350 * @return {Roo.Toolbar.Item} The element's item
30352 addText : function(text){
30353 return this.addItem(new Roo.Toolbar.TextItem(text));
30357 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
30358 * @param {Number} index The index where the item is to be inserted
30359 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
30360 * @return {Roo.Toolbar.Button/Item}
30362 insertButton : function(index, item){
30363 if(item instanceof Array){
30365 for(var i = 0, len = item.length; i < len; i++) {
30366 buttons.push(this.insertButton(index + i, item[i]));
30370 if (!(item instanceof Roo.Toolbar.Button)){
30371 item = new Roo.Toolbar.Button(item);
30373 var td = document.createElement("td");
30374 this.tr.insertBefore(td, this.tr.childNodes[index]);
30376 this.items.insert(index, item);
30381 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
30382 * @param {Object} config
30383 * @return {Roo.Toolbar.Item} The element's item
30385 addDom : function(config, returnEl){
30386 var td = this.nextBlock();
30387 Roo.DomHelper.overwrite(td, config);
30388 var ti = new Roo.Toolbar.Item(td.firstChild);
30390 this.items.add(ti);
30395 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
30396 * @type Roo.util.MixedCollection
30401 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc).
30402 * Note: the field should not have been rendered yet. For a field that has already been
30403 * rendered, use {@link #addElement}.
30404 * @param {Roo.form.Field} field
30405 * @return {Roo.ToolbarItem}
30409 addField : function(field) {
30410 if (!this.fields) {
30412 this.fields = new Roo.util.MixedCollection(false, function(o){
30413 return o.id || ("item" + (++autoId));
30418 var td = this.nextBlock();
30420 var ti = new Roo.Toolbar.Item(td.firstChild);
30422 this.items.add(ti);
30423 this.fields.add(field);
30434 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
30435 this.el.child('div').hide();
30443 this.el.child('div').show();
30447 nextBlock : function(){
30448 var td = document.createElement("td");
30449 this.tr.appendChild(td);
30454 destroy : function(){
30455 if(this.items){ // rendered?
30456 Roo.destroy.apply(Roo, this.items.items);
30458 if(this.fields){ // rendered?
30459 Roo.destroy.apply(Roo, this.fields.items);
30461 Roo.Element.uncache(this.el, this.tr);
30466 * @class Roo.Toolbar.Item
30467 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
30469 * Creates a new Item
30470 * @param {HTMLElement} el
30472 Roo.Toolbar.Item = function(el){
30474 if (typeof (el.xtype) != 'undefined') {
30479 this.el = Roo.getDom(el);
30480 this.id = Roo.id(this.el);
30481 this.hidden = false;
30486 * Fires when the button is rendered
30487 * @param {Button} this
30491 Roo.Toolbar.Item.superclass.constructor.call(this,cfg);
30493 Roo.extend(Roo.Toolbar.Item, Roo.util.Observable, {
30494 //Roo.Toolbar.Item.prototype = {
30497 * Get this item's HTML Element
30498 * @return {HTMLElement}
30500 getEl : function(){
30505 render : function(td){
30508 td.appendChild(this.el);
30510 this.fireEvent('render', this);
30514 * Removes and destroys this item.
30516 destroy : function(){
30517 this.td.parentNode.removeChild(this.td);
30524 this.hidden = false;
30525 this.td.style.display = "";
30532 this.hidden = true;
30533 this.td.style.display = "none";
30537 * Convenience function for boolean show/hide.
30538 * @param {Boolean} visible true to show/false to hide
30540 setVisible: function(visible){
30549 * Try to focus this item.
30551 focus : function(){
30552 Roo.fly(this.el).focus();
30556 * Disables this item.
30558 disable : function(){
30559 Roo.fly(this.td).addClass("x-item-disabled");
30560 this.disabled = true;
30561 this.el.disabled = true;
30565 * Enables this item.
30567 enable : function(){
30568 Roo.fly(this.td).removeClass("x-item-disabled");
30569 this.disabled = false;
30570 this.el.disabled = false;
30576 * @class Roo.Toolbar.Separator
30577 * @extends Roo.Toolbar.Item
30578 * A simple toolbar separator class
30580 * Creates a new Separator
30582 Roo.Toolbar.Separator = function(cfg){
30584 var s = document.createElement("span");
30585 s.className = "ytb-sep";
30590 Roo.Toolbar.Separator.superclass.constructor.call(this, cfg || s);
30592 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
30593 enable:Roo.emptyFn,
30594 disable:Roo.emptyFn,
30599 * @class Roo.Toolbar.Spacer
30600 * @extends Roo.Toolbar.Item
30601 * A simple element that adds extra horizontal space to a toolbar.
30603 * Creates a new Spacer
30605 Roo.Toolbar.Spacer = function(cfg){
30606 var s = document.createElement("div");
30607 s.className = "ytb-spacer";
30611 Roo.Toolbar.Spacer.superclass.constructor.call(this, cfg || s);
30613 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
30614 enable:Roo.emptyFn,
30615 disable:Roo.emptyFn,
30620 * @class Roo.Toolbar.Fill
30621 * @extends Roo.Toolbar.Spacer
30622 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
30624 * Creates a new Spacer
30626 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
30628 render : function(td){
30629 td.style.width = '100%';
30630 Roo.Toolbar.Fill.superclass.render.call(this, td);
30635 * @class Roo.Toolbar.TextItem
30636 * @extends Roo.Toolbar.Item
30637 * A simple class that renders text directly into a toolbar.
30639 * Creates a new TextItem
30640 * @cfg {string} text
30642 Roo.Toolbar.TextItem = function(cfg){
30643 var text = cfg || "";
30644 if (typeof(cfg) == 'object') {
30645 text = cfg.text || "";
30649 var s = document.createElement("span");
30650 s.className = "ytb-text";
30651 s.innerHTML = text;
30656 Roo.Toolbar.TextItem.superclass.constructor.call(this, cfg || s);
30658 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
30661 enable:Roo.emptyFn,
30662 disable:Roo.emptyFn,
30667 * @class Roo.Toolbar.Button
30668 * @extends Roo.Button
30669 * A button that renders into a toolbar.
30671 * Creates a new Button
30672 * @param {Object} config A standard {@link Roo.Button} config object
30674 Roo.Toolbar.Button = function(config){
30675 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
30677 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
30678 render : function(td){
30680 Roo.Toolbar.Button.superclass.render.call(this, td);
30684 * Removes and destroys this button
30686 destroy : function(){
30687 Roo.Toolbar.Button.superclass.destroy.call(this);
30688 this.td.parentNode.removeChild(this.td);
30692 * Shows this button
30695 this.hidden = false;
30696 this.td.style.display = "";
30700 * Hides this button
30703 this.hidden = true;
30704 this.td.style.display = "none";
30708 * Disables this item
30710 disable : function(){
30711 Roo.fly(this.td).addClass("x-item-disabled");
30712 this.disabled = true;
30716 * Enables this item
30718 enable : function(){
30719 Roo.fly(this.td).removeClass("x-item-disabled");
30720 this.disabled = false;
30723 // backwards compat
30724 Roo.ToolbarButton = Roo.Toolbar.Button;
30727 * @class Roo.Toolbar.SplitButton
30728 * @extends Roo.SplitButton
30729 * A menu button that renders into a toolbar.
30731 * Creates a new SplitButton
30732 * @param {Object} config A standard {@link Roo.SplitButton} config object
30734 Roo.Toolbar.SplitButton = function(config){
30735 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
30737 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
30738 render : function(td){
30740 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
30744 * Removes and destroys this button
30746 destroy : function(){
30747 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
30748 this.td.parentNode.removeChild(this.td);
30752 * Shows this button
30755 this.hidden = false;
30756 this.td.style.display = "";
30760 * Hides this button
30763 this.hidden = true;
30764 this.td.style.display = "none";
30768 // backwards compat
30769 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
30771 * Ext JS Library 1.1.1
30772 * Copyright(c) 2006-2007, Ext JS, LLC.
30774 * Originally Released Under LGPL - original licence link has changed is not relivant.
30777 * <script type="text/javascript">
30781 * @class Roo.PagingToolbar
30782 * @extends Roo.Toolbar
30783 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
30785 * Create a new PagingToolbar
30786 * @param {Object} config The config object
30788 Roo.PagingToolbar = function(el, ds, config)
30790 // old args format still supported... - xtype is prefered..
30791 if (typeof(el) == 'object' && el.xtype) {
30792 // created from xtype...
30794 ds = el.dataSource;
30795 el = config.container;
30798 if (config.items) {
30799 items = config.items;
30803 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
30806 this.renderButtons(this.el);
30809 // supprot items array.
30811 Roo.each(items, function(e) {
30812 this.add(Roo.factory(e));
30817 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
30819 * @cfg {Roo.data.Store} dataSource
30820 * The underlying data store providing the paged data
30823 * @cfg {String/HTMLElement/Element} container
30824 * container The id or element that will contain the toolbar
30827 * @cfg {Boolean} displayInfo
30828 * True to display the displayMsg (defaults to false)
30831 * @cfg {Number} pageSize
30832 * The number of records to display per page (defaults to 20)
30836 * @cfg {String} displayMsg
30837 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
30839 displayMsg : 'Displaying {0} - {1} of {2}',
30841 * @cfg {String} emptyMsg
30842 * The message to display when no records are found (defaults to "No data to display")
30844 emptyMsg : 'No data to display',
30846 * Customizable piece of the default paging text (defaults to "Page")
30849 beforePageText : "Page",
30851 * Customizable piece of the default paging text (defaults to "of %0")
30854 afterPageText : "of {0}",
30856 * Customizable piece of the default paging text (defaults to "First Page")
30859 firstText : "First Page",
30861 * Customizable piece of the default paging text (defaults to "Previous Page")
30864 prevText : "Previous Page",
30866 * Customizable piece of the default paging text (defaults to "Next Page")
30869 nextText : "Next Page",
30871 * Customizable piece of the default paging text (defaults to "Last Page")
30874 lastText : "Last Page",
30876 * Customizable piece of the default paging text (defaults to "Refresh")
30879 refreshText : "Refresh",
30882 renderButtons : function(el){
30883 Roo.PagingToolbar.superclass.render.call(this, el);
30884 this.first = this.addButton({
30885 tooltip: this.firstText,
30886 cls: "x-btn-icon x-grid-page-first",
30888 handler: this.onClick.createDelegate(this, ["first"])
30890 this.prev = this.addButton({
30891 tooltip: this.prevText,
30892 cls: "x-btn-icon x-grid-page-prev",
30894 handler: this.onClick.createDelegate(this, ["prev"])
30896 //this.addSeparator();
30897 this.add(this.beforePageText);
30898 this.field = Roo.get(this.addDom({
30903 cls: "x-grid-page-number"
30905 this.field.on("keydown", this.onPagingKeydown, this);
30906 this.field.on("focus", function(){this.dom.select();});
30907 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
30908 this.field.setHeight(18);
30909 //this.addSeparator();
30910 this.next = this.addButton({
30911 tooltip: this.nextText,
30912 cls: "x-btn-icon x-grid-page-next",
30914 handler: this.onClick.createDelegate(this, ["next"])
30916 this.last = this.addButton({
30917 tooltip: this.lastText,
30918 cls: "x-btn-icon x-grid-page-last",
30920 handler: this.onClick.createDelegate(this, ["last"])
30922 //this.addSeparator();
30923 this.loading = this.addButton({
30924 tooltip: this.refreshText,
30925 cls: "x-btn-icon x-grid-loading",
30926 handler: this.onClick.createDelegate(this, ["refresh"])
30929 if(this.displayInfo){
30930 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
30935 updateInfo : function(){
30936 if(this.displayEl){
30937 var count = this.ds.getCount();
30938 var msg = count == 0 ?
30942 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
30944 this.displayEl.update(msg);
30949 onLoad : function(ds, r, o){
30950 this.cursor = o.params ? o.params.start : 0;
30951 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
30953 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
30954 this.field.dom.value = ap;
30955 this.first.setDisabled(ap == 1);
30956 this.prev.setDisabled(ap == 1);
30957 this.next.setDisabled(ap == ps);
30958 this.last.setDisabled(ap == ps);
30959 this.loading.enable();
30964 getPageData : function(){
30965 var total = this.ds.getTotalCount();
30968 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
30969 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
30974 onLoadError : function(){
30975 this.loading.enable();
30979 onPagingKeydown : function(e){
30980 var k = e.getKey();
30981 var d = this.getPageData();
30983 var v = this.field.dom.value, pageNum;
30984 if(!v || isNaN(pageNum = parseInt(v, 10))){
30985 this.field.dom.value = d.activePage;
30988 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
30989 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
30992 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))
30994 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
30995 this.field.dom.value = pageNum;
30996 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
30999 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
31001 var v = this.field.dom.value, pageNum;
31002 var increment = (e.shiftKey) ? 10 : 1;
31003 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
31006 if(!v || isNaN(pageNum = parseInt(v, 10))) {
31007 this.field.dom.value = d.activePage;
31010 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
31012 this.field.dom.value = parseInt(v, 10) + increment;
31013 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
31014 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
31021 beforeLoad : function(){
31023 this.loading.disable();
31028 onClick : function(which){
31032 ds.load({params:{start: 0, limit: this.pageSize}});
31035 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
31038 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
31041 var total = ds.getTotalCount();
31042 var extra = total % this.pageSize;
31043 var lastStart = extra ? (total - extra) : total-this.pageSize;
31044 ds.load({params:{start: lastStart, limit: this.pageSize}});
31047 ds.load({params:{start: this.cursor, limit: this.pageSize}});
31053 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
31054 * @param {Roo.data.Store} store The data store to unbind
31056 unbind : function(ds){
31057 ds.un("beforeload", this.beforeLoad, this);
31058 ds.un("load", this.onLoad, this);
31059 ds.un("loadexception", this.onLoadError, this);
31060 ds.un("remove", this.updateInfo, this);
31061 ds.un("add", this.updateInfo, this);
31062 this.ds = undefined;
31066 * Binds the paging toolbar to the specified {@link Roo.data.Store}
31067 * @param {Roo.data.Store} store The data store to bind
31069 bind : function(ds){
31070 ds.on("beforeload", this.beforeLoad, this);
31071 ds.on("load", this.onLoad, this);
31072 ds.on("loadexception", this.onLoadError, this);
31073 ds.on("remove", this.updateInfo, this);
31074 ds.on("add", this.updateInfo, this);
31079 * Ext JS Library 1.1.1
31080 * Copyright(c) 2006-2007, Ext JS, LLC.
31082 * Originally Released Under LGPL - original licence link has changed is not relivant.
31085 * <script type="text/javascript">
31089 * @class Roo.Resizable
31090 * @extends Roo.util.Observable
31091 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
31092 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
31093 * 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
31094 * the element will be wrapped for you automatically.</p>
31095 * <p>Here is the list of valid resize handles:</p>
31098 ------ -------------------
31107 'hd' horizontal drag
31110 * <p>Here's an example showing the creation of a typical Resizable:</p>
31112 var resizer = new Roo.Resizable("element-id", {
31120 resizer.on("resize", myHandler);
31122 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
31123 * resizer.east.setDisplayed(false);</p>
31124 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
31125 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
31126 * resize operation's new size (defaults to [0, 0])
31127 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
31128 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
31129 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
31130 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
31131 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
31132 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
31133 * @cfg {Number} width The width of the element in pixels (defaults to null)
31134 * @cfg {Number} height The height of the element in pixels (defaults to null)
31135 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
31136 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
31137 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
31138 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
31139 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
31140 * in favor of the handles config option (defaults to false)
31141 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
31142 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
31143 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
31144 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
31145 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
31146 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
31147 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
31148 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
31149 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
31150 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
31151 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
31153 * Create a new resizable component
31154 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
31155 * @param {Object} config configuration options
31157 Roo.Resizable = function(el, config)
31159 this.el = Roo.get(el);
31161 if(config && config.wrap){
31162 config.resizeChild = this.el;
31163 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
31164 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
31165 this.el.setStyle("overflow", "hidden");
31166 this.el.setPositioning(config.resizeChild.getPositioning());
31167 config.resizeChild.clearPositioning();
31168 if(!config.width || !config.height){
31169 var csize = config.resizeChild.getSize();
31170 this.el.setSize(csize.width, csize.height);
31172 if(config.pinned && !config.adjustments){
31173 config.adjustments = "auto";
31177 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
31178 this.proxy.unselectable();
31179 this.proxy.enableDisplayMode('block');
31181 Roo.apply(this, config);
31184 this.disableTrackOver = true;
31185 this.el.addClass("x-resizable-pinned");
31187 // if the element isn't positioned, make it relative
31188 var position = this.el.getStyle("position");
31189 if(position != "absolute" && position != "fixed"){
31190 this.el.setStyle("position", "relative");
31192 if(!this.handles){ // no handles passed, must be legacy style
31193 this.handles = 's,e,se';
31194 if(this.multiDirectional){
31195 this.handles += ',n,w';
31198 if(this.handles == "all"){
31199 this.handles = "n s e w ne nw se sw";
31201 var hs = this.handles.split(/\s*?[,;]\s*?| /);
31202 var ps = Roo.Resizable.positions;
31203 for(var i = 0, len = hs.length; i < len; i++){
31204 if(hs[i] && ps[hs[i]]){
31205 var pos = ps[hs[i]];
31206 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
31210 this.corner = this.southeast;
31212 // updateBox = the box can move..
31213 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
31214 this.updateBox = true;
31217 this.activeHandle = null;
31219 if(this.resizeChild){
31220 if(typeof this.resizeChild == "boolean"){
31221 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
31223 this.resizeChild = Roo.get(this.resizeChild, true);
31227 if(this.adjustments == "auto"){
31228 var rc = this.resizeChild;
31229 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
31230 if(rc && (hw || hn)){
31231 rc.position("relative");
31232 rc.setLeft(hw ? hw.el.getWidth() : 0);
31233 rc.setTop(hn ? hn.el.getHeight() : 0);
31235 this.adjustments = [
31236 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
31237 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
31241 if(this.draggable){
31242 this.dd = this.dynamic ?
31243 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
31244 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
31250 * @event beforeresize
31251 * Fired before resize is allowed. Set enabled to false to cancel resize.
31252 * @param {Roo.Resizable} this
31253 * @param {Roo.EventObject} e The mousedown event
31255 "beforeresize" : true,
31258 * Fired a resizing.
31259 * @param {Roo.Resizable} this
31260 * @param {Number} x The new x position
31261 * @param {Number} y The new y position
31262 * @param {Number} w The new w width
31263 * @param {Number} h The new h hight
31264 * @param {Roo.EventObject} e The mouseup event
31269 * Fired after a resize.
31270 * @param {Roo.Resizable} this
31271 * @param {Number} width The new width
31272 * @param {Number} height The new height
31273 * @param {Roo.EventObject} e The mouseup event
31278 if(this.width !== null && this.height !== null){
31279 this.resizeTo(this.width, this.height);
31281 this.updateChildSize();
31284 this.el.dom.style.zoom = 1;
31286 Roo.Resizable.superclass.constructor.call(this);
31289 Roo.extend(Roo.Resizable, Roo.util.Observable, {
31290 resizeChild : false,
31291 adjustments : [0, 0],
31301 multiDirectional : false,
31302 disableTrackOver : false,
31303 easing : 'easeOutStrong',
31304 widthIncrement : 0,
31305 heightIncrement : 0,
31309 preserveRatio : false,
31310 transparent: false,
31316 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
31318 constrainTo: undefined,
31320 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
31322 resizeRegion: undefined,
31326 * Perform a manual resize
31327 * @param {Number} width
31328 * @param {Number} height
31330 resizeTo : function(width, height){
31331 this.el.setSize(width, height);
31332 this.updateChildSize();
31333 this.fireEvent("resize", this, width, height, null);
31337 startSizing : function(e, handle){
31338 this.fireEvent("beforeresize", this, e);
31339 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
31342 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
31343 this.overlay.unselectable();
31344 this.overlay.enableDisplayMode("block");
31345 this.overlay.on("mousemove", this.onMouseMove, this);
31346 this.overlay.on("mouseup", this.onMouseUp, this);
31348 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
31350 this.resizing = true;
31351 this.startBox = this.el.getBox();
31352 this.startPoint = e.getXY();
31353 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
31354 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
31356 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
31357 this.overlay.show();
31359 if(this.constrainTo) {
31360 var ct = Roo.get(this.constrainTo);
31361 this.resizeRegion = ct.getRegion().adjust(
31362 ct.getFrameWidth('t'),
31363 ct.getFrameWidth('l'),
31364 -ct.getFrameWidth('b'),
31365 -ct.getFrameWidth('r')
31369 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
31371 this.proxy.setBox(this.startBox);
31373 this.proxy.setStyle('visibility', 'visible');
31379 onMouseDown : function(handle, e){
31382 this.activeHandle = handle;
31383 this.startSizing(e, handle);
31388 onMouseUp : function(e){
31389 var size = this.resizeElement();
31390 this.resizing = false;
31392 this.overlay.hide();
31394 this.fireEvent("resize", this, size.width, size.height, e);
31398 updateChildSize : function(){
31400 if(this.resizeChild){
31402 var child = this.resizeChild;
31403 var adj = this.adjustments;
31404 if(el.dom.offsetWidth){
31405 var b = el.getSize(true);
31406 child.setSize(b.width+adj[0], b.height+adj[1]);
31408 // Second call here for IE
31409 // The first call enables instant resizing and
31410 // the second call corrects scroll bars if they
31413 setTimeout(function(){
31414 if(el.dom.offsetWidth){
31415 var b = el.getSize(true);
31416 child.setSize(b.width+adj[0], b.height+adj[1]);
31424 snap : function(value, inc, min){
31425 if(!inc || !value) {
31428 var newValue = value;
31429 var m = value % inc;
31432 newValue = value + (inc-m);
31434 newValue = value - m;
31437 return Math.max(min, newValue);
31441 resizeElement : function(){
31442 var box = this.proxy.getBox();
31443 if(this.updateBox){
31444 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
31446 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
31448 this.updateChildSize();
31456 constrain : function(v, diff, m, mx){
31459 }else if(v - diff > mx){
31466 onMouseMove : function(e){
31469 try{// try catch so if something goes wrong the user doesn't get hung
31471 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
31475 //var curXY = this.startPoint;
31476 var curSize = this.curSize || this.startBox;
31477 var x = this.startBox.x, y = this.startBox.y;
31478 var ox = x, oy = y;
31479 var w = curSize.width, h = curSize.height;
31480 var ow = w, oh = h;
31481 var mw = this.minWidth, mh = this.minHeight;
31482 var mxw = this.maxWidth, mxh = this.maxHeight;
31483 var wi = this.widthIncrement;
31484 var hi = this.heightIncrement;
31486 var eventXY = e.getXY();
31487 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
31488 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
31490 var pos = this.activeHandle.position;
31495 w = Math.min(Math.max(mw, w), mxw);
31500 h = Math.min(Math.max(mh, h), mxh);
31505 w = Math.min(Math.max(mw, w), mxw);
31506 h = Math.min(Math.max(mh, h), mxh);
31509 diffY = this.constrain(h, diffY, mh, mxh);
31516 var adiffX = Math.abs(diffX);
31517 var sub = (adiffX % wi); // how much
31518 if (sub > (wi/2)) { // far enough to snap
31519 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
31521 // remove difference..
31522 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
31526 x = Math.max(this.minX, x);
31529 diffX = this.constrain(w, diffX, mw, mxw);
31535 w = Math.min(Math.max(mw, w), mxw);
31536 diffY = this.constrain(h, diffY, mh, mxh);
31541 diffX = this.constrain(w, diffX, mw, mxw);
31542 diffY = this.constrain(h, diffY, mh, mxh);
31549 diffX = this.constrain(w, diffX, mw, mxw);
31551 h = Math.min(Math.max(mh, h), mxh);
31557 var sw = this.snap(w, wi, mw);
31558 var sh = this.snap(h, hi, mh);
31559 if(sw != w || sh != h){
31582 if(this.preserveRatio){
31587 h = Math.min(Math.max(mh, h), mxh);
31592 w = Math.min(Math.max(mw, w), mxw);
31597 w = Math.min(Math.max(mw, w), mxw);
31603 w = Math.min(Math.max(mw, w), mxw);
31609 h = Math.min(Math.max(mh, h), mxh);
31617 h = Math.min(Math.max(mh, h), mxh);
31627 h = Math.min(Math.max(mh, h), mxh);
31635 if (pos == 'hdrag') {
31638 this.proxy.setBounds(x, y, w, h);
31640 this.resizeElement();
31644 this.fireEvent("resizing", this, x, y, w, h, e);
31648 handleOver : function(){
31650 this.el.addClass("x-resizable-over");
31655 handleOut : function(){
31656 if(!this.resizing){
31657 this.el.removeClass("x-resizable-over");
31662 * Returns the element this component is bound to.
31663 * @return {Roo.Element}
31665 getEl : function(){
31670 * Returns the resizeChild element (or null).
31671 * @return {Roo.Element}
31673 getResizeChild : function(){
31674 return this.resizeChild;
31676 groupHandler : function()
31681 * Destroys this resizable. If the element was wrapped and
31682 * removeEl is not true then the element remains.
31683 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
31685 destroy : function(removeEl){
31686 this.proxy.remove();
31688 this.overlay.removeAllListeners();
31689 this.overlay.remove();
31691 var ps = Roo.Resizable.positions;
31693 if(typeof ps[k] != "function" && this[ps[k]]){
31694 var h = this[ps[k]];
31695 h.el.removeAllListeners();
31700 this.el.update("");
31707 // hash to map config positions to true positions
31708 Roo.Resizable.positions = {
31709 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
31714 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
31716 // only initialize the template if resizable is used
31717 var tpl = Roo.DomHelper.createTemplate(
31718 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
31721 Roo.Resizable.Handle.prototype.tpl = tpl;
31723 this.position = pos;
31725 // show north drag fro topdra
31726 var handlepos = pos == 'hdrag' ? 'north' : pos;
31728 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
31729 if (pos == 'hdrag') {
31730 this.el.setStyle('cursor', 'pointer');
31732 this.el.unselectable();
31734 this.el.setOpacity(0);
31736 this.el.on("mousedown", this.onMouseDown, this);
31737 if(!disableTrackOver){
31738 this.el.on("mouseover", this.onMouseOver, this);
31739 this.el.on("mouseout", this.onMouseOut, this);
31744 Roo.Resizable.Handle.prototype = {
31745 afterResize : function(rz){
31750 onMouseDown : function(e){
31751 this.rz.onMouseDown(this, e);
31754 onMouseOver : function(e){
31755 this.rz.handleOver(this, e);
31758 onMouseOut : function(e){
31759 this.rz.handleOut(this, e);
31763 * Ext JS Library 1.1.1
31764 * Copyright(c) 2006-2007, Ext JS, LLC.
31766 * Originally Released Under LGPL - original licence link has changed is not relivant.
31769 * <script type="text/javascript">
31773 * @class Roo.Editor
31774 * @extends Roo.Component
31775 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
31777 * Create a new Editor
31778 * @param {Roo.form.Field} field The Field object (or descendant)
31779 * @param {Object} config The config object
31781 Roo.Editor = function(field, config){
31782 Roo.Editor.superclass.constructor.call(this, config);
31783 this.field = field;
31786 * @event beforestartedit
31787 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
31788 * false from the handler of this event.
31789 * @param {Editor} this
31790 * @param {Roo.Element} boundEl The underlying element bound to this editor
31791 * @param {Mixed} value The field value being set
31793 "beforestartedit" : true,
31796 * Fires when this editor is displayed
31797 * @param {Roo.Element} boundEl The underlying element bound to this editor
31798 * @param {Mixed} value The starting field value
31800 "startedit" : true,
31802 * @event beforecomplete
31803 * Fires after a change has been made to the field, but before the change is reflected in the underlying
31804 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
31805 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
31806 * event will not fire since no edit actually occurred.
31807 * @param {Editor} this
31808 * @param {Mixed} value The current field value
31809 * @param {Mixed} startValue The original field value
31811 "beforecomplete" : true,
31814 * Fires after editing is complete and any changed value has been written to the underlying field.
31815 * @param {Editor} this
31816 * @param {Mixed} value The current field value
31817 * @param {Mixed} startValue The original field value
31821 * @event specialkey
31822 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
31823 * {@link Roo.EventObject#getKey} to determine which key was pressed.
31824 * @param {Roo.form.Field} this
31825 * @param {Roo.EventObject} e The event object
31827 "specialkey" : true
31831 Roo.extend(Roo.Editor, Roo.Component, {
31833 * @cfg {Boolean/String} autosize
31834 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
31835 * or "height" to adopt the height only (defaults to false)
31838 * @cfg {Boolean} revertInvalid
31839 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
31840 * validation fails (defaults to true)
31843 * @cfg {Boolean} ignoreNoChange
31844 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
31845 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
31846 * will never be ignored.
31849 * @cfg {Boolean} hideEl
31850 * False to keep the bound element visible while the editor is displayed (defaults to true)
31853 * @cfg {Mixed} value
31854 * The data value of the underlying field (defaults to "")
31858 * @cfg {String} alignment
31859 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
31863 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
31864 * for bottom-right shadow (defaults to "frame")
31868 * @cfg {Boolean} constrain True to constrain the editor to the viewport
31872 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
31874 completeOnEnter : false,
31876 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
31878 cancelOnEsc : false,
31880 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
31885 onRender : function(ct, position){
31886 this.el = new Roo.Layer({
31887 shadow: this.shadow,
31893 constrain: this.constrain
31895 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
31896 if(this.field.msgTarget != 'title'){
31897 this.field.msgTarget = 'qtip';
31899 this.field.render(this.el);
31901 this.field.el.dom.setAttribute('autocomplete', 'off');
31903 this.field.on("specialkey", this.onSpecialKey, this);
31904 if(this.swallowKeys){
31905 this.field.el.swallowEvent(['keydown','keypress']);
31908 this.field.on("blur", this.onBlur, this);
31909 if(this.field.grow){
31910 this.field.on("autosize", this.el.sync, this.el, {delay:1});
31914 onSpecialKey : function(field, e)
31916 //Roo.log('editor onSpecialKey');
31917 if(this.completeOnEnter && e.getKey() == e.ENTER){
31919 this.completeEdit();
31922 // do not fire special key otherwise it might hide close the editor...
31923 if(e.getKey() == e.ENTER){
31926 if(this.cancelOnEsc && e.getKey() == e.ESC){
31930 this.fireEvent('specialkey', field, e);
31935 * Starts the editing process and shows the editor.
31936 * @param {String/HTMLElement/Element} el The element to edit
31937 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
31938 * to the innerHTML of el.
31940 startEdit : function(el, value){
31942 this.completeEdit();
31944 this.boundEl = Roo.get(el);
31945 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
31946 if(!this.rendered){
31947 this.render(this.parentEl || document.body);
31949 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
31952 this.startValue = v;
31953 this.field.setValue(v);
31955 var sz = this.boundEl.getSize();
31956 switch(this.autoSize){
31958 this.setSize(sz.width, "");
31961 this.setSize("", sz.height);
31964 this.setSize(sz.width, sz.height);
31967 this.el.alignTo(this.boundEl, this.alignment);
31968 this.editing = true;
31970 Roo.QuickTips.disable();
31976 * Sets the height and width of this editor.
31977 * @param {Number} width The new width
31978 * @param {Number} height The new height
31980 setSize : function(w, h){
31981 this.field.setSize(w, h);
31988 * Realigns the editor to the bound field based on the current alignment config value.
31990 realign : function(){
31991 this.el.alignTo(this.boundEl, this.alignment);
31995 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
31996 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
31998 completeEdit : function(remainVisible){
32002 var v = this.getValue();
32003 if(this.revertInvalid !== false && !this.field.isValid()){
32004 v = this.startValue;
32005 this.cancelEdit(true);
32007 if(String(v) === String(this.startValue) && this.ignoreNoChange){
32008 this.editing = false;
32012 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
32013 this.editing = false;
32014 if(this.updateEl && this.boundEl){
32015 this.boundEl.update(v);
32017 if(remainVisible !== true){
32020 this.fireEvent("complete", this, v, this.startValue);
32025 onShow : function(){
32027 if(this.hideEl !== false){
32028 this.boundEl.hide();
32031 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
32032 this.fixIEFocus = true;
32033 this.deferredFocus.defer(50, this);
32035 this.field.focus();
32037 this.fireEvent("startedit", this.boundEl, this.startValue);
32040 deferredFocus : function(){
32042 this.field.focus();
32047 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
32048 * reverted to the original starting value.
32049 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
32050 * cancel (defaults to false)
32052 cancelEdit : function(remainVisible){
32054 this.setValue(this.startValue);
32055 if(remainVisible !== true){
32062 onBlur : function(){
32063 if(this.allowBlur !== true && this.editing){
32064 this.completeEdit();
32069 onHide : function(){
32071 this.completeEdit();
32075 if(this.field.collapse){
32076 this.field.collapse();
32079 if(this.hideEl !== false){
32080 this.boundEl.show();
32083 Roo.QuickTips.enable();
32088 * Sets the data value of the editor
32089 * @param {Mixed} value Any valid value supported by the underlying field
32091 setValue : function(v){
32092 this.field.setValue(v);
32096 * Gets the data value of the editor
32097 * @return {Mixed} The data value
32099 getValue : function(){
32100 return this.field.getValue();
32104 * Ext JS Library 1.1.1
32105 * Copyright(c) 2006-2007, Ext JS, LLC.
32107 * Originally Released Under LGPL - original licence link has changed is not relivant.
32110 * <script type="text/javascript">
32114 * @class Roo.BasicDialog
32115 * @extends Roo.util.Observable
32116 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
32118 var dlg = new Roo.BasicDialog("my-dlg", {
32127 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
32128 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
32129 dlg.addButton('Cancel', dlg.hide, dlg);
32132 <b>A Dialog should always be a direct child of the body element.</b>
32133 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
32134 * @cfg {String} title Default text to display in the title bar (defaults to null)
32135 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
32136 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
32137 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
32138 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
32139 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
32140 * (defaults to null with no animation)
32141 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
32142 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
32143 * property for valid values (defaults to 'all')
32144 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
32145 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
32146 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
32147 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
32148 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
32149 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
32150 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
32151 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
32152 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
32153 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
32154 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
32155 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
32156 * draggable = true (defaults to false)
32157 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
32158 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
32159 * shadow (defaults to false)
32160 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
32161 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
32162 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
32163 * @cfg {Array} buttons Array of buttons
32164 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
32166 * Create a new BasicDialog.
32167 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
32168 * @param {Object} config Configuration options
32170 Roo.BasicDialog = function(el, config){
32171 this.el = Roo.get(el);
32172 var dh = Roo.DomHelper;
32173 if(!this.el && config && config.autoCreate){
32174 if(typeof config.autoCreate == "object"){
32175 if(!config.autoCreate.id){
32176 config.autoCreate.id = el;
32178 this.el = dh.append(document.body,
32179 config.autoCreate, true);
32181 this.el = dh.append(document.body,
32182 {tag: "div", id: el, style:'visibility:hidden;'}, true);
32186 el.setDisplayed(true);
32187 el.hide = this.hideAction;
32189 el.addClass("x-dlg");
32191 Roo.apply(this, config);
32193 this.proxy = el.createProxy("x-dlg-proxy");
32194 this.proxy.hide = this.hideAction;
32195 this.proxy.setOpacity(.5);
32199 el.setWidth(config.width);
32202 el.setHeight(config.height);
32204 this.size = el.getSize();
32205 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
32206 this.xy = [config.x,config.y];
32208 this.xy = el.getCenterXY(true);
32210 /** The header element @type Roo.Element */
32211 this.header = el.child("> .x-dlg-hd");
32212 /** The body element @type Roo.Element */
32213 this.body = el.child("> .x-dlg-bd");
32214 /** The footer element @type Roo.Element */
32215 this.footer = el.child("> .x-dlg-ft");
32218 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
32221 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
32224 this.header.unselectable();
32226 this.header.update(this.title);
32228 // this element allows the dialog to be focused for keyboard event
32229 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
32230 this.focusEl.swallowEvent("click", true);
32232 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
32234 // wrap the body and footer for special rendering
32235 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
32237 this.bwrap.dom.appendChild(this.footer.dom);
32240 this.bg = this.el.createChild({
32241 tag: "div", cls:"x-dlg-bg",
32242 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
32244 this.centerBg = this.bg.child("div.x-dlg-bg-center");
32247 if(this.autoScroll !== false && !this.autoTabs){
32248 this.body.setStyle("overflow", "auto");
32251 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
32253 if(this.closable !== false){
32254 this.el.addClass("x-dlg-closable");
32255 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
32256 this.close.on("click", this.closeClick, this);
32257 this.close.addClassOnOver("x-dlg-close-over");
32259 if(this.collapsible !== false){
32260 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
32261 this.collapseBtn.on("click", this.collapseClick, this);
32262 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
32263 this.header.on("dblclick", this.collapseClick, this);
32265 if(this.resizable !== false){
32266 this.el.addClass("x-dlg-resizable");
32267 this.resizer = new Roo.Resizable(el, {
32268 minWidth: this.minWidth || 80,
32269 minHeight:this.minHeight || 80,
32270 handles: this.resizeHandles || "all",
32273 this.resizer.on("beforeresize", this.beforeResize, this);
32274 this.resizer.on("resize", this.onResize, this);
32276 if(this.draggable !== false){
32277 el.addClass("x-dlg-draggable");
32278 if (!this.proxyDrag) {
32279 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
32282 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
32284 dd.setHandleElId(this.header.id);
32285 dd.endDrag = this.endMove.createDelegate(this);
32286 dd.startDrag = this.startMove.createDelegate(this);
32287 dd.onDrag = this.onDrag.createDelegate(this);
32292 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
32293 this.mask.enableDisplayMode("block");
32295 this.el.addClass("x-dlg-modal");
32298 this.shadow = new Roo.Shadow({
32299 mode : typeof this.shadow == "string" ? this.shadow : "sides",
32300 offset : this.shadowOffset
32303 this.shadowOffset = 0;
32305 if(Roo.useShims && this.shim !== false){
32306 this.shim = this.el.createShim();
32307 this.shim.hide = this.hideAction;
32315 if (this.buttons) {
32316 var bts= this.buttons;
32318 Roo.each(bts, function(b) {
32327 * Fires when a key is pressed
32328 * @param {Roo.BasicDialog} this
32329 * @param {Roo.EventObject} e
32334 * Fires when this dialog is moved by the user.
32335 * @param {Roo.BasicDialog} this
32336 * @param {Number} x The new page X
32337 * @param {Number} y The new page Y
32342 * Fires when this dialog is resized by the user.
32343 * @param {Roo.BasicDialog} this
32344 * @param {Number} width The new width
32345 * @param {Number} height The new height
32349 * @event beforehide
32350 * Fires before this dialog is hidden.
32351 * @param {Roo.BasicDialog} this
32353 "beforehide" : true,
32356 * Fires when this dialog is hidden.
32357 * @param {Roo.BasicDialog} this
32361 * @event beforeshow
32362 * Fires before this dialog is shown.
32363 * @param {Roo.BasicDialog} this
32365 "beforeshow" : true,
32368 * Fires when this dialog is shown.
32369 * @param {Roo.BasicDialog} this
32373 el.on("keydown", this.onKeyDown, this);
32374 el.on("mousedown", this.toFront, this);
32375 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
32377 Roo.DialogManager.register(this);
32378 Roo.BasicDialog.superclass.constructor.call(this);
32381 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
32382 shadowOffset: Roo.isIE ? 6 : 5,
32385 minButtonWidth: 75,
32386 defaultButton: null,
32387 buttonAlign: "right",
32392 * Sets the dialog title text
32393 * @param {String} text The title text to display
32394 * @return {Roo.BasicDialog} this
32396 setTitle : function(text){
32397 this.header.update(text);
32402 closeClick : function(){
32407 collapseClick : function(){
32408 this[this.collapsed ? "expand" : "collapse"]();
32412 * Collapses the dialog to its minimized state (only the title bar is visible).
32413 * Equivalent to the user clicking the collapse dialog button.
32415 collapse : function(){
32416 if(!this.collapsed){
32417 this.collapsed = true;
32418 this.el.addClass("x-dlg-collapsed");
32419 this.restoreHeight = this.el.getHeight();
32420 this.resizeTo(this.el.getWidth(), this.header.getHeight());
32425 * Expands a collapsed dialog back to its normal state. Equivalent to the user
32426 * clicking the expand dialog button.
32428 expand : function(){
32429 if(this.collapsed){
32430 this.collapsed = false;
32431 this.el.removeClass("x-dlg-collapsed");
32432 this.resizeTo(this.el.getWidth(), this.restoreHeight);
32437 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
32438 * @return {Roo.TabPanel} The tabs component
32440 initTabs : function(){
32441 var tabs = this.getTabs();
32442 while(tabs.getTab(0)){
32445 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
32447 tabs.addTab(Roo.id(dom), dom.title);
32455 beforeResize : function(){
32456 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
32460 onResize : function(){
32461 this.refreshSize();
32462 this.syncBodyHeight();
32463 this.adjustAssets();
32465 this.fireEvent("resize", this, this.size.width, this.size.height);
32469 onKeyDown : function(e){
32470 if(this.isVisible()){
32471 this.fireEvent("keydown", this, e);
32476 * Resizes the dialog.
32477 * @param {Number} width
32478 * @param {Number} height
32479 * @return {Roo.BasicDialog} this
32481 resizeTo : function(width, height){
32482 this.el.setSize(width, height);
32483 this.size = {width: width, height: height};
32484 this.syncBodyHeight();
32485 if(this.fixedcenter){
32488 if(this.isVisible()){
32489 this.constrainXY();
32490 this.adjustAssets();
32492 this.fireEvent("resize", this, width, height);
32498 * Resizes the dialog to fit the specified content size.
32499 * @param {Number} width
32500 * @param {Number} height
32501 * @return {Roo.BasicDialog} this
32503 setContentSize : function(w, h){
32504 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
32505 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
32506 //if(!this.el.isBorderBox()){
32507 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
32508 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
32511 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
32512 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
32514 this.resizeTo(w, h);
32519 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
32520 * executed in response to a particular key being pressed while the dialog is active.
32521 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
32522 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
32523 * @param {Function} fn The function to call
32524 * @param {Object} scope (optional) The scope of the function
32525 * @return {Roo.BasicDialog} this
32527 addKeyListener : function(key, fn, scope){
32528 var keyCode, shift, ctrl, alt;
32529 if(typeof key == "object" && !(key instanceof Array)){
32530 keyCode = key["key"];
32531 shift = key["shift"];
32532 ctrl = key["ctrl"];
32537 var handler = function(dlg, e){
32538 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
32539 var k = e.getKey();
32540 if(keyCode instanceof Array){
32541 for(var i = 0, len = keyCode.length; i < len; i++){
32542 if(keyCode[i] == k){
32543 fn.call(scope || window, dlg, k, e);
32549 fn.call(scope || window, dlg, k, e);
32554 this.on("keydown", handler);
32559 * Returns the TabPanel component (creates it if it doesn't exist).
32560 * Note: If you wish to simply check for the existence of tabs without creating them,
32561 * check for a null 'tabs' property.
32562 * @return {Roo.TabPanel} The tabs component
32564 getTabs : function(){
32566 this.el.addClass("x-dlg-auto-tabs");
32567 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
32568 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
32574 * Adds a button to the footer section of the dialog.
32575 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
32576 * object or a valid Roo.DomHelper element config
32577 * @param {Function} handler The function called when the button is clicked
32578 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
32579 * @return {Roo.Button} The new button
32581 addButton : function(config, handler, scope){
32582 var dh = Roo.DomHelper;
32584 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
32586 if(!this.btnContainer){
32587 var tb = this.footer.createChild({
32589 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
32590 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
32592 this.btnContainer = tb.firstChild.firstChild.firstChild;
32597 minWidth: this.minButtonWidth,
32600 if(typeof config == "string"){
32601 bconfig.text = config;
32604 bconfig.dhconfig = config;
32606 Roo.apply(bconfig, config);
32610 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
32611 bconfig.position = Math.max(0, bconfig.position);
32612 fc = this.btnContainer.childNodes[bconfig.position];
32615 var btn = new Roo.Button(
32617 this.btnContainer.insertBefore(document.createElement("td"),fc)
32618 : this.btnContainer.appendChild(document.createElement("td")),
32619 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
32622 this.syncBodyHeight();
32625 * Array of all the buttons that have been added to this dialog via addButton
32630 this.buttons.push(btn);
32635 * Sets the default button to be focused when the dialog is displayed.
32636 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
32637 * @return {Roo.BasicDialog} this
32639 setDefaultButton : function(btn){
32640 this.defaultButton = btn;
32645 getHeaderFooterHeight : function(safe){
32648 height += this.header.getHeight();
32651 var fm = this.footer.getMargins();
32652 height += (this.footer.getHeight()+fm.top+fm.bottom);
32654 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
32655 height += this.centerBg.getPadding("tb");
32660 syncBodyHeight : function()
32662 var bd = this.body, // the text
32663 cb = this.centerBg, // wrapper around bottom.. but does not seem to be used..
32665 var height = this.size.height - this.getHeaderFooterHeight(false);
32666 bd.setHeight(height-bd.getMargins("tb"));
32667 var hh = this.header.getHeight();
32668 var h = this.size.height-hh;
32671 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
32672 bw.setHeight(h-cb.getPadding("tb"));
32674 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
32675 bd.setWidth(bw.getWidth(true));
32677 this.tabs.syncHeight();
32679 this.tabs.el.repaint();
32685 * Restores the previous state of the dialog if Roo.state is configured.
32686 * @return {Roo.BasicDialog} this
32688 restoreState : function(){
32689 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
32690 if(box && box.width){
32691 this.xy = [box.x, box.y];
32692 this.resizeTo(box.width, box.height);
32698 beforeShow : function(){
32700 if(this.fixedcenter){
32701 this.xy = this.el.getCenterXY(true);
32704 Roo.get(document.body).addClass("x-body-masked");
32705 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
32708 this.constrainXY();
32712 animShow : function(){
32713 var b = Roo.get(this.animateTarget).getBox();
32714 this.proxy.setSize(b.width, b.height);
32715 this.proxy.setLocation(b.x, b.y);
32717 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
32718 true, .35, this.showEl.createDelegate(this));
32722 * Shows the dialog.
32723 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
32724 * @return {Roo.BasicDialog} this
32726 show : function(animateTarget){
32727 if (this.fireEvent("beforeshow", this) === false){
32730 if(this.syncHeightBeforeShow){
32731 this.syncBodyHeight();
32732 }else if(this.firstShow){
32733 this.firstShow = false;
32734 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
32736 this.animateTarget = animateTarget || this.animateTarget;
32737 if(!this.el.isVisible()){
32739 if(this.animateTarget && Roo.get(this.animateTarget)){
32749 showEl : function(){
32751 this.el.setXY(this.xy);
32753 this.adjustAssets(true);
32756 // IE peekaboo bug - fix found by Dave Fenwick
32760 this.fireEvent("show", this);
32764 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
32765 * dialog itself will receive focus.
32767 focus : function(){
32768 if(this.defaultButton){
32769 this.defaultButton.focus();
32771 this.focusEl.focus();
32776 constrainXY : function(){
32777 if(this.constraintoviewport !== false){
32778 if(!this.viewSize){
32779 if(this.container){
32780 var s = this.container.getSize();
32781 this.viewSize = [s.width, s.height];
32783 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
32786 var s = Roo.get(this.container||document).getScroll();
32788 var x = this.xy[0], y = this.xy[1];
32789 var w = this.size.width, h = this.size.height;
32790 var vw = this.viewSize[0], vh = this.viewSize[1];
32791 // only move it if it needs it
32793 // first validate right/bottom
32794 if(x + w > vw+s.left){
32798 if(y + h > vh+s.top){
32802 // then make sure top/left isn't negative
32814 if(this.isVisible()){
32815 this.el.setLocation(x, y);
32816 this.adjustAssets();
32823 onDrag : function(){
32824 if(!this.proxyDrag){
32825 this.xy = this.el.getXY();
32826 this.adjustAssets();
32831 adjustAssets : function(doShow){
32832 var x = this.xy[0], y = this.xy[1];
32833 var w = this.size.width, h = this.size.height;
32834 if(doShow === true){
32836 this.shadow.show(this.el);
32842 if(this.shadow && this.shadow.isVisible()){
32843 this.shadow.show(this.el);
32845 if(this.shim && this.shim.isVisible()){
32846 this.shim.setBounds(x, y, w, h);
32851 adjustViewport : function(w, h){
32853 w = Roo.lib.Dom.getViewWidth();
32854 h = Roo.lib.Dom.getViewHeight();
32857 this.viewSize = [w, h];
32858 if(this.modal && this.mask.isVisible()){
32859 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
32860 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
32862 if(this.isVisible()){
32863 this.constrainXY();
32868 * Destroys this dialog and all its supporting elements (including any tabs, shim,
32869 * shadow, proxy, mask, etc.) Also removes all event listeners.
32870 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
32872 destroy : function(removeEl){
32873 if(this.isVisible()){
32874 this.animateTarget = null;
32877 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
32879 this.tabs.destroy(removeEl);
32892 for(var i = 0, len = this.buttons.length; i < len; i++){
32893 this.buttons[i].destroy();
32896 this.el.removeAllListeners();
32897 if(removeEl === true){
32898 this.el.update("");
32901 Roo.DialogManager.unregister(this);
32905 startMove : function(){
32906 if(this.proxyDrag){
32909 if(this.constraintoviewport !== false){
32910 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
32915 endMove : function(){
32916 if(!this.proxyDrag){
32917 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
32919 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
32922 this.refreshSize();
32923 this.adjustAssets();
32925 this.fireEvent("move", this, this.xy[0], this.xy[1]);
32929 * Brings this dialog to the front of any other visible dialogs
32930 * @return {Roo.BasicDialog} this
32932 toFront : function(){
32933 Roo.DialogManager.bringToFront(this);
32938 * Sends this dialog to the back (under) of any other visible dialogs
32939 * @return {Roo.BasicDialog} this
32941 toBack : function(){
32942 Roo.DialogManager.sendToBack(this);
32947 * Centers this dialog in the viewport
32948 * @return {Roo.BasicDialog} this
32950 center : function(){
32951 var xy = this.el.getCenterXY(true);
32952 this.moveTo(xy[0], xy[1]);
32957 * Moves the dialog's top-left corner to the specified point
32958 * @param {Number} x
32959 * @param {Number} y
32960 * @return {Roo.BasicDialog} this
32962 moveTo : function(x, y){
32964 if(this.isVisible()){
32965 this.el.setXY(this.xy);
32966 this.adjustAssets();
32972 * Aligns the dialog to the specified element
32973 * @param {String/HTMLElement/Roo.Element} element The element to align to.
32974 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
32975 * @param {Array} offsets (optional) Offset the positioning by [x, y]
32976 * @return {Roo.BasicDialog} this
32978 alignTo : function(element, position, offsets){
32979 this.xy = this.el.getAlignToXY(element, position, offsets);
32980 if(this.isVisible()){
32981 this.el.setXY(this.xy);
32982 this.adjustAssets();
32988 * Anchors an element to another element and realigns it when the window is resized.
32989 * @param {String/HTMLElement/Roo.Element} element The element to align to.
32990 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
32991 * @param {Array} offsets (optional) Offset the positioning by [x, y]
32992 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
32993 * is a number, it is used as the buffer delay (defaults to 50ms).
32994 * @return {Roo.BasicDialog} this
32996 anchorTo : function(el, alignment, offsets, monitorScroll){
32997 var action = function(){
32998 this.alignTo(el, alignment, offsets);
33000 Roo.EventManager.onWindowResize(action, this);
33001 var tm = typeof monitorScroll;
33002 if(tm != 'undefined'){
33003 Roo.EventManager.on(window, 'scroll', action, this,
33004 {buffer: tm == 'number' ? monitorScroll : 50});
33011 * Returns true if the dialog is visible
33012 * @return {Boolean}
33014 isVisible : function(){
33015 return this.el.isVisible();
33019 animHide : function(callback){
33020 var b = Roo.get(this.animateTarget).getBox();
33022 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
33024 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
33025 this.hideEl.createDelegate(this, [callback]));
33029 * Hides the dialog.
33030 * @param {Function} callback (optional) Function to call when the dialog is hidden
33031 * @return {Roo.BasicDialog} this
33033 hide : function(callback){
33034 if (this.fireEvent("beforehide", this) === false){
33038 this.shadow.hide();
33043 // sometimes animateTarget seems to get set.. causing problems...
33044 // this just double checks..
33045 if(this.animateTarget && Roo.get(this.animateTarget)) {
33046 this.animHide(callback);
33049 this.hideEl(callback);
33055 hideEl : function(callback){
33059 Roo.get(document.body).removeClass("x-body-masked");
33061 this.fireEvent("hide", this);
33062 if(typeof callback == "function"){
33068 hideAction : function(){
33069 this.setLeft("-10000px");
33070 this.setTop("-10000px");
33071 this.setStyle("visibility", "hidden");
33075 refreshSize : function(){
33076 this.size = this.el.getSize();
33077 this.xy = this.el.getXY();
33078 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
33082 // z-index is managed by the DialogManager and may be overwritten at any time
33083 setZIndex : function(index){
33085 this.mask.setStyle("z-index", index);
33088 this.shim.setStyle("z-index", ++index);
33091 this.shadow.setZIndex(++index);
33093 this.el.setStyle("z-index", ++index);
33095 this.proxy.setStyle("z-index", ++index);
33098 this.resizer.proxy.setStyle("z-index", ++index);
33101 this.lastZIndex = index;
33105 * Returns the element for this dialog
33106 * @return {Roo.Element} The underlying dialog Element
33108 getEl : function(){
33114 * @class Roo.DialogManager
33115 * Provides global access to BasicDialogs that have been created and
33116 * support for z-indexing (layering) multiple open dialogs.
33118 Roo.DialogManager = function(){
33120 var accessList = [];
33124 var sortDialogs = function(d1, d2){
33125 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
33129 var orderDialogs = function(){
33130 accessList.sort(sortDialogs);
33131 var seed = Roo.DialogManager.zseed;
33132 for(var i = 0, len = accessList.length; i < len; i++){
33133 var dlg = accessList[i];
33135 dlg.setZIndex(seed + (i*10));
33142 * The starting z-index for BasicDialogs (defaults to 9000)
33143 * @type Number The z-index value
33148 register : function(dlg){
33149 list[dlg.id] = dlg;
33150 accessList.push(dlg);
33154 unregister : function(dlg){
33155 delete list[dlg.id];
33158 if(!accessList.indexOf){
33159 for( i = 0, len = accessList.length; i < len; i++){
33160 if(accessList[i] == dlg){
33161 accessList.splice(i, 1);
33166 i = accessList.indexOf(dlg);
33168 accessList.splice(i, 1);
33174 * Gets a registered dialog by id
33175 * @param {String/Object} id The id of the dialog or a dialog
33176 * @return {Roo.BasicDialog} this
33178 get : function(id){
33179 return typeof id == "object" ? id : list[id];
33183 * Brings the specified dialog to the front
33184 * @param {String/Object} dlg The id of the dialog or a dialog
33185 * @return {Roo.BasicDialog} this
33187 bringToFront : function(dlg){
33188 dlg = this.get(dlg);
33191 dlg._lastAccess = new Date().getTime();
33198 * Sends the specified dialog to the back
33199 * @param {String/Object} dlg The id of the dialog or a dialog
33200 * @return {Roo.BasicDialog} this
33202 sendToBack : function(dlg){
33203 dlg = this.get(dlg);
33204 dlg._lastAccess = -(new Date().getTime());
33210 * Hides all dialogs
33212 hideAll : function(){
33213 for(var id in list){
33214 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
33223 * @class Roo.LayoutDialog
33224 * @extends Roo.BasicDialog
33225 * Dialog which provides adjustments for working with a layout in a Dialog.
33226 * Add your necessary layout config options to the dialog's config.<br>
33227 * Example usage (including a nested layout):
33230 dialog = new Roo.LayoutDialog("download-dlg", {
33239 // layout config merges with the dialog config
33241 tabPosition: "top",
33242 alwaysShowTabs: true
33245 dialog.addKeyListener(27, dialog.hide, dialog);
33246 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
33247 dialog.addButton("Build It!", this.getDownload, this);
33249 // we can even add nested layouts
33250 var innerLayout = new Roo.BorderLayout("dl-inner", {
33260 innerLayout.beginUpdate();
33261 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
33262 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
33263 innerLayout.endUpdate(true);
33265 var layout = dialog.getLayout();
33266 layout.beginUpdate();
33267 layout.add("center", new Roo.ContentPanel("standard-panel",
33268 {title: "Download the Source", fitToFrame:true}));
33269 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
33270 {title: "Build your own roo.js"}));
33271 layout.getRegion("center").showPanel(sp);
33272 layout.endUpdate();
33276 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
33277 * @param {Object} config configuration options
33279 Roo.LayoutDialog = function(el, cfg){
33282 if (typeof(cfg) == 'undefined') {
33283 config = Roo.apply({}, el);
33284 // not sure why we use documentElement here.. - it should always be body.
33285 // IE7 borks horribly if we use documentElement.
33286 // webkit also does not like documentElement - it creates a body element...
33287 el = Roo.get( document.body || document.documentElement ).createChild();
33288 //config.autoCreate = true;
33292 config.autoTabs = false;
33293 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
33294 this.body.setStyle({overflow:"hidden", position:"relative"});
33295 this.layout = new Roo.BorderLayout(this.body.dom, config);
33296 this.layout.monitorWindowResize = false;
33297 this.el.addClass("x-dlg-auto-layout");
33298 // fix case when center region overwrites center function
33299 this.center = Roo.BasicDialog.prototype.center;
33300 this.on("show", this.layout.layout, this.layout, true);
33301 if (config.items) {
33302 var xitems = config.items;
33303 delete config.items;
33304 Roo.each(xitems, this.addxtype, this);
33309 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
33311 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
33314 endUpdate : function(){
33315 this.layout.endUpdate();
33319 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
33322 beginUpdate : function(){
33323 this.layout.beginUpdate();
33327 * Get the BorderLayout for this dialog
33328 * @return {Roo.BorderLayout}
33330 getLayout : function(){
33331 return this.layout;
33334 showEl : function(){
33335 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
33337 this.layout.layout();
33342 // Use the syncHeightBeforeShow config option to control this automatically
33343 syncBodyHeight : function(){
33344 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
33345 if(this.layout){this.layout.layout();}
33349 * Add an xtype element (actually adds to the layout.)
33350 * @return {Object} xdata xtype object data.
33353 addxtype : function(c) {
33354 return this.layout.addxtype(c);
33358 * Ext JS Library 1.1.1
33359 * Copyright(c) 2006-2007, Ext JS, LLC.
33361 * Originally Released Under LGPL - original licence link has changed is not relivant.
33364 * <script type="text/javascript">
33368 * @class Roo.MessageBox
33369 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
33373 Roo.Msg.alert('Status', 'Changes saved successfully.');
33375 // Prompt for user data:
33376 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
33378 // process text value...
33382 // Show a dialog using config options:
33384 title:'Save Changes?',
33385 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
33386 buttons: Roo.Msg.YESNOCANCEL,
33393 Roo.MessageBox = function(){
33394 var dlg, opt, mask, waitTimer;
33395 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
33396 var buttons, activeTextEl, bwidth;
33399 var handleButton = function(button){
33401 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
33405 var handleHide = function(){
33406 if(opt && opt.cls){
33407 dlg.el.removeClass(opt.cls);
33410 Roo.TaskMgr.stop(waitTimer);
33416 var updateButtons = function(b){
33419 buttons["ok"].hide();
33420 buttons["cancel"].hide();
33421 buttons["yes"].hide();
33422 buttons["no"].hide();
33423 dlg.footer.dom.style.display = 'none';
33426 dlg.footer.dom.style.display = '';
33427 for(var k in buttons){
33428 if(typeof buttons[k] != "function"){
33431 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
33432 width += buttons[k].el.getWidth()+15;
33442 var handleEsc = function(d, k, e){
33443 if(opt && opt.closable !== false){
33453 * Returns a reference to the underlying {@link Roo.BasicDialog} element
33454 * @return {Roo.BasicDialog} The BasicDialog element
33456 getDialog : function(){
33458 dlg = new Roo.BasicDialog("x-msg-box", {
33463 constraintoviewport:false,
33465 collapsible : false,
33468 width:400, height:100,
33469 buttonAlign:"center",
33470 closeClick : function(){
33471 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
33472 handleButton("no");
33474 handleButton("cancel");
33478 dlg.on("hide", handleHide);
33480 dlg.addKeyListener(27, handleEsc);
33482 var bt = this.buttonText;
33483 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
33484 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
33485 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
33486 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
33487 bodyEl = dlg.body.createChild({
33489 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>'
33491 msgEl = bodyEl.dom.firstChild;
33492 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
33493 textboxEl.enableDisplayMode();
33494 textboxEl.addKeyListener([10,13], function(){
33495 if(dlg.isVisible() && opt && opt.buttons){
33496 if(opt.buttons.ok){
33497 handleButton("ok");
33498 }else if(opt.buttons.yes){
33499 handleButton("yes");
33503 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
33504 textareaEl.enableDisplayMode();
33505 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
33506 progressEl.enableDisplayMode();
33507 var pf = progressEl.dom.firstChild;
33509 pp = Roo.get(pf.firstChild);
33510 pp.setHeight(pf.offsetHeight);
33518 * Updates the message box body text
33519 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
33520 * the XHTML-compliant non-breaking space character '&#160;')
33521 * @return {Roo.MessageBox} This message box
33523 updateText : function(text){
33524 if(!dlg.isVisible() && !opt.width){
33525 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
33527 msgEl.innerHTML = text || ' ';
33529 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
33530 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
33532 Math.min(opt.width || cw , this.maxWidth),
33533 Math.max(opt.minWidth || this.minWidth, bwidth)
33536 activeTextEl.setWidth(w);
33538 if(dlg.isVisible()){
33539 dlg.fixedcenter = false;
33541 // to big, make it scroll. = But as usual stupid IE does not support
33544 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
33545 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
33546 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
33548 bodyEl.dom.style.height = '';
33549 bodyEl.dom.style.overflowY = '';
33552 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
33554 bodyEl.dom.style.overflowX = '';
33557 dlg.setContentSize(w, bodyEl.getHeight());
33558 if(dlg.isVisible()){
33559 dlg.fixedcenter = true;
33565 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
33566 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
33567 * @param {Number} value Any number between 0 and 1 (e.g., .5)
33568 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
33569 * @return {Roo.MessageBox} This message box
33571 updateProgress : function(value, text){
33573 this.updateText(text);
33575 if (pp) { // weird bug on my firefox - for some reason this is not defined
33576 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
33582 * Returns true if the message box is currently displayed
33583 * @return {Boolean} True if the message box is visible, else false
33585 isVisible : function(){
33586 return dlg && dlg.isVisible();
33590 * Hides the message box if it is displayed
33593 if(this.isVisible()){
33599 * Displays a new message box, or reinitializes an existing message box, based on the config options
33600 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
33601 * The following config object properties are supported:
33603 Property Type Description
33604 ---------- --------------- ------------------------------------------------------------------------------------
33605 animEl String/Element An id or Element from which the message box should animate as it opens and
33606 closes (defaults to undefined)
33607 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
33608 cancel:'Bar'}), or false to not show any buttons (defaults to false)
33609 closable Boolean False to hide the top-right close button (defaults to true). Note that
33610 progress and wait dialogs will ignore this property and always hide the
33611 close button as they can only be closed programmatically.
33612 cls String A custom CSS class to apply to the message box element
33613 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
33614 displayed (defaults to 75)
33615 fn Function A callback function to execute after closing the dialog. The arguments to the
33616 function will be btn (the name of the button that was clicked, if applicable,
33617 e.g. "ok"), and text (the value of the active text field, if applicable).
33618 Progress and wait dialogs will ignore this option since they do not respond to
33619 user actions and can only be closed programmatically, so any required function
33620 should be called by the same code after it closes the dialog.
33621 icon String A CSS class that provides a background image to be used as an icon for
33622 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
33623 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
33624 minWidth Number The minimum width in pixels of the message box (defaults to 100)
33625 modal Boolean False to allow user interaction with the page while the message box is
33626 displayed (defaults to true)
33627 msg String A string that will replace the existing message box body text (defaults
33628 to the XHTML-compliant non-breaking space character ' ')
33629 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
33630 progress Boolean True to display a progress bar (defaults to false)
33631 progressText String The text to display inside the progress bar if progress = true (defaults to '')
33632 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
33633 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
33634 title String The title text
33635 value String The string value to set into the active textbox element if displayed
33636 wait Boolean True to display a progress bar (defaults to false)
33637 width Number The width of the dialog in pixels
33644 msg: 'Please enter your address:',
33646 buttons: Roo.MessageBox.OKCANCEL,
33649 animEl: 'addAddressBtn'
33652 * @param {Object} config Configuration options
33653 * @return {Roo.MessageBox} This message box
33655 show : function(options)
33658 // this causes nightmares if you show one dialog after another
33659 // especially on callbacks..
33661 if(this.isVisible()){
33664 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
33665 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
33666 Roo.log("New Dialog Message:" + options.msg )
33667 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
33668 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
33671 var d = this.getDialog();
33673 d.setTitle(opt.title || " ");
33674 d.close.setDisplayed(opt.closable !== false);
33675 activeTextEl = textboxEl;
33676 opt.prompt = opt.prompt || (opt.multiline ? true : false);
33681 textareaEl.setHeight(typeof opt.multiline == "number" ?
33682 opt.multiline : this.defaultTextHeight);
33683 activeTextEl = textareaEl;
33692 progressEl.setDisplayed(opt.progress === true);
33693 this.updateProgress(0);
33694 activeTextEl.dom.value = opt.value || "";
33696 dlg.setDefaultButton(activeTextEl);
33698 var bs = opt.buttons;
33701 db = buttons["ok"];
33702 }else if(bs && bs.yes){
33703 db = buttons["yes"];
33705 dlg.setDefaultButton(db);
33707 bwidth = updateButtons(opt.buttons);
33708 this.updateText(opt.msg);
33710 d.el.addClass(opt.cls);
33712 d.proxyDrag = opt.proxyDrag === true;
33713 d.modal = opt.modal !== false;
33714 d.mask = opt.modal !== false ? mask : false;
33715 if(!d.isVisible()){
33716 // force it to the end of the z-index stack so it gets a cursor in FF
33717 document.body.appendChild(dlg.el.dom);
33718 d.animateTarget = null;
33719 d.show(options.animEl);
33725 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
33726 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
33727 * and closing the message box when the process is complete.
33728 * @param {String} title The title bar text
33729 * @param {String} msg The message box body text
33730 * @return {Roo.MessageBox} This message box
33732 progress : function(title, msg){
33739 minWidth: this.minProgressWidth,
33746 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
33747 * If a callback function is passed it will be called after the user clicks the button, and the
33748 * id of the button that was clicked will be passed as the only parameter to the callback
33749 * (could also be the top-right close button).
33750 * @param {String} title The title bar text
33751 * @param {String} msg The message box body text
33752 * @param {Function} fn (optional) The callback function invoked after the message box is closed
33753 * @param {Object} scope (optional) The scope of the callback function
33754 * @return {Roo.MessageBox} This message box
33756 alert : function(title, msg, fn, scope){
33769 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
33770 * interaction while waiting for a long-running process to complete that does not have defined intervals.
33771 * You are responsible for closing the message box when the process is complete.
33772 * @param {String} msg The message box body text
33773 * @param {String} title (optional) The title bar text
33774 * @return {Roo.MessageBox} This message box
33776 wait : function(msg, title){
33787 waitTimer = Roo.TaskMgr.start({
33789 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
33797 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
33798 * If a callback function is passed it will be called after the user clicks either button, and the id of the
33799 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
33800 * @param {String} title The title bar text
33801 * @param {String} msg The message box body text
33802 * @param {Function} fn (optional) The callback function invoked after the message box is closed
33803 * @param {Object} scope (optional) The scope of the callback function
33804 * @return {Roo.MessageBox} This message box
33806 confirm : function(title, msg, fn, scope){
33810 buttons: this.YESNO,
33819 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
33820 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
33821 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
33822 * (could also be the top-right close button) and the text that was entered will be passed as the two
33823 * parameters to the callback.
33824 * @param {String} title The title bar text
33825 * @param {String} msg The message box body text
33826 * @param {Function} fn (optional) The callback function invoked after the message box is closed
33827 * @param {Object} scope (optional) The scope of the callback function
33828 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
33829 * property, or the height in pixels to create the textbox (defaults to false / single-line)
33830 * @return {Roo.MessageBox} This message box
33832 prompt : function(title, msg, fn, scope, multiline){
33836 buttons: this.OKCANCEL,
33841 multiline: multiline,
33848 * Button config that displays a single OK button
33853 * Button config that displays Yes and No buttons
33856 YESNO : {yes:true, no:true},
33858 * Button config that displays OK and Cancel buttons
33861 OKCANCEL : {ok:true, cancel:true},
33863 * Button config that displays Yes, No and Cancel buttons
33866 YESNOCANCEL : {yes:true, no:true, cancel:true},
33869 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
33872 defaultTextHeight : 75,
33874 * The maximum width in pixels of the message box (defaults to 600)
33879 * The minimum width in pixels of the message box (defaults to 100)
33884 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
33885 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
33888 minProgressWidth : 250,
33890 * An object containing the default button text strings that can be overriden for localized language support.
33891 * Supported properties are: ok, cancel, yes and no.
33892 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
33905 * Shorthand for {@link Roo.MessageBox}
33907 Roo.Msg = Roo.MessageBox;/*
33909 * Ext JS Library 1.1.1
33910 * Copyright(c) 2006-2007, Ext JS, LLC.
33912 * Originally Released Under LGPL - original licence link has changed is not relivant.
33915 * <script type="text/javascript">
33918 * @class Roo.QuickTips
33919 * Provides attractive and customizable tooltips for any element.
33922 Roo.QuickTips = function(){
33923 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
33924 var ce, bd, xy, dd;
33925 var visible = false, disabled = true, inited = false;
33926 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
33928 var onOver = function(e){
33932 var t = e.getTarget();
33933 if(!t || t.nodeType !== 1 || t == document || t == document.body){
33936 if(ce && t == ce.el){
33937 clearTimeout(hideProc);
33940 if(t && tagEls[t.id]){
33941 tagEls[t.id].el = t;
33942 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
33945 var ttp, et = Roo.fly(t);
33946 var ns = cfg.namespace;
33947 if(tm.interceptTitles && t.title){
33950 t.removeAttribute("title");
33951 e.preventDefault();
33953 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute) || et.getAttributeNS(cfg.alt_namespace, cfg.attribute) ;
33956 showProc = show.defer(tm.showDelay, tm, [{
33958 text: ttp.replace(/\\n/g,'<br/>'),
33959 width: et.getAttributeNS(ns, cfg.width),
33960 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
33961 title: et.getAttributeNS(ns, cfg.title),
33962 cls: et.getAttributeNS(ns, cfg.cls)
33967 var onOut = function(e){
33968 clearTimeout(showProc);
33969 var t = e.getTarget();
33970 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
33971 hideProc = setTimeout(hide, tm.hideDelay);
33975 var onMove = function(e){
33981 if(tm.trackMouse && ce){
33986 var onDown = function(e){
33987 clearTimeout(showProc);
33988 clearTimeout(hideProc);
33990 if(tm.hideOnClick){
33993 tm.enable.defer(100, tm);
33998 var getPad = function(){
33999 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
34002 var show = function(o){
34006 clearTimeout(dismissProc);
34008 if(removeCls){ // in case manually hidden
34009 el.removeClass(removeCls);
34013 el.addClass(ce.cls);
34014 removeCls = ce.cls;
34017 tipTitle.update(ce.title);
34020 tipTitle.update('');
34023 el.dom.style.width = tm.maxWidth+'px';
34024 //tipBody.dom.style.width = '';
34025 tipBodyText.update(o.text);
34026 var p = getPad(), w = ce.width;
34028 var td = tipBodyText.dom;
34029 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
34030 if(aw > tm.maxWidth){
34032 }else if(aw < tm.minWidth){
34038 //tipBody.setWidth(w);
34039 el.setWidth(parseInt(w, 10) + p);
34040 if(ce.autoHide === false){
34041 close.setDisplayed(true);
34046 close.setDisplayed(false);
34052 el.avoidY = xy[1]-18;
34057 el.setStyle("visibility", "visible");
34058 el.fadeIn({callback: afterShow});
34064 var afterShow = function(){
34068 if(tm.autoDismiss && ce.autoHide !== false){
34069 dismissProc = setTimeout(hide, tm.autoDismissDelay);
34074 var hide = function(noanim){
34075 clearTimeout(dismissProc);
34076 clearTimeout(hideProc);
34078 if(el.isVisible()){
34080 if(noanim !== true && tm.animate){
34081 el.fadeOut({callback: afterHide});
34088 var afterHide = function(){
34091 el.removeClass(removeCls);
34098 * @cfg {Number} minWidth
34099 * The minimum width of the quick tip (defaults to 40)
34103 * @cfg {Number} maxWidth
34104 * The maximum width of the quick tip (defaults to 300)
34108 * @cfg {Boolean} interceptTitles
34109 * True to automatically use the element's DOM title value if available (defaults to false)
34111 interceptTitles : false,
34113 * @cfg {Boolean} trackMouse
34114 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
34116 trackMouse : false,
34118 * @cfg {Boolean} hideOnClick
34119 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
34121 hideOnClick : true,
34123 * @cfg {Number} showDelay
34124 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
34128 * @cfg {Number} hideDelay
34129 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
34133 * @cfg {Boolean} autoHide
34134 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
34135 * Used in conjunction with hideDelay.
34140 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
34141 * (defaults to true). Used in conjunction with autoDismissDelay.
34143 autoDismiss : true,
34146 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
34148 autoDismissDelay : 5000,
34150 * @cfg {Boolean} animate
34151 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
34156 * @cfg {String} title
34157 * Title text to display (defaults to ''). This can be any valid HTML markup.
34161 * @cfg {String} text
34162 * Body text to display (defaults to ''). This can be any valid HTML markup.
34166 * @cfg {String} cls
34167 * A CSS class to apply to the base quick tip element (defaults to '').
34171 * @cfg {Number} width
34172 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
34173 * minWidth or maxWidth.
34178 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
34179 * or display QuickTips in a page.
34182 tm = Roo.QuickTips;
34183 cfg = tm.tagConfig;
34185 if(!Roo.isReady){ // allow calling of init() before onReady
34186 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
34189 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
34190 el.fxDefaults = {stopFx: true};
34191 // maximum custom styling
34192 //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>');
34193 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>');
34194 tipTitle = el.child('h3');
34195 tipTitle.enableDisplayMode("block");
34196 tipBody = el.child('div.x-tip-bd');
34197 tipBodyText = el.child('div.x-tip-bd-inner');
34198 //bdLeft = el.child('div.x-tip-bd-left');
34199 //bdRight = el.child('div.x-tip-bd-right');
34200 close = el.child('div.x-tip-close');
34201 close.enableDisplayMode("block");
34202 close.on("click", hide);
34203 var d = Roo.get(document);
34204 d.on("mousedown", onDown);
34205 d.on("mouseover", onOver);
34206 d.on("mouseout", onOut);
34207 d.on("mousemove", onMove);
34208 esc = d.addKeyListener(27, hide);
34211 dd = el.initDD("default", null, {
34212 onDrag : function(){
34216 dd.setHandleElId(tipTitle.id);
34225 * Configures a new quick tip instance and assigns it to a target element. The following config options
34228 Property Type Description
34229 ---------- --------------------- ------------------------------------------------------------------------
34230 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
34232 * @param {Object} config The config object
34234 register : function(config){
34235 var cs = config instanceof Array ? config : arguments;
34236 for(var i = 0, len = cs.length; i < len; i++) {
34238 var target = c.target;
34240 if(target instanceof Array){
34241 for(var j = 0, jlen = target.length; j < jlen; j++){
34242 tagEls[target[j]] = c;
34245 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
34252 * Removes this quick tip from its element and destroys it.
34253 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
34255 unregister : function(el){
34256 delete tagEls[Roo.id(el)];
34260 * Enable this quick tip.
34262 enable : function(){
34263 if(inited && disabled){
34265 if(locks.length < 1){
34272 * Disable this quick tip.
34274 disable : function(){
34276 clearTimeout(showProc);
34277 clearTimeout(hideProc);
34278 clearTimeout(dismissProc);
34286 * Returns true if the quick tip is enabled, else false.
34288 isEnabled : function(){
34294 namespace : "roo", // was ext?? this may break..
34295 alt_namespace : "ext",
34296 attribute : "qtip",
34306 // backwards compat
34307 Roo.QuickTips.tips = Roo.QuickTips.register;/*
34309 * Ext JS Library 1.1.1
34310 * Copyright(c) 2006-2007, Ext JS, LLC.
34312 * Originally Released Under LGPL - original licence link has changed is not relivant.
34315 * <script type="text/javascript">
34320 * @class Roo.tree.TreePanel
34321 * @extends Roo.data.Tree
34323 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
34324 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
34325 * @cfg {Boolean} enableDD true to enable drag and drop
34326 * @cfg {Boolean} enableDrag true to enable just drag
34327 * @cfg {Boolean} enableDrop true to enable just drop
34328 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
34329 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
34330 * @cfg {String} ddGroup The DD group this TreePanel belongs to
34331 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
34332 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
34333 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
34334 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
34335 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
34336 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
34337 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
34338 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
34339 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
34340 * @cfg {Object|Roo.tree.TreeEditor} editor The TreeEditor or xtype data to display when clicked.
34341 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
34342 * @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>
34343 * @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>
34346 * @param {String/HTMLElement/Element} el The container element
34347 * @param {Object} config
34349 Roo.tree.TreePanel = function(el, config){
34351 var loader = false;
34353 root = config.root;
34354 delete config.root;
34356 if (config.loader) {
34357 loader = config.loader;
34358 delete config.loader;
34361 Roo.apply(this, config);
34362 Roo.tree.TreePanel.superclass.constructor.call(this);
34363 this.el = Roo.get(el);
34364 this.el.addClass('x-tree');
34365 //console.log(root);
34367 this.setRootNode( Roo.factory(root, Roo.tree));
34370 this.loader = Roo.factory(loader, Roo.tree);
34373 * Read-only. The id of the container element becomes this TreePanel's id.
34375 this.id = this.el.id;
34378 * @event beforeload
34379 * Fires before a node is loaded, return false to cancel
34380 * @param {Node} node The node being loaded
34382 "beforeload" : true,
34385 * Fires when a node is loaded
34386 * @param {Node} node The node that was loaded
34390 * @event textchange
34391 * Fires when the text for a node is changed
34392 * @param {Node} node The node
34393 * @param {String} text The new text
34394 * @param {String} oldText The old text
34396 "textchange" : true,
34398 * @event beforeexpand
34399 * Fires before a node is expanded, return false to cancel.
34400 * @param {Node} node The node
34401 * @param {Boolean} deep
34402 * @param {Boolean} anim
34404 "beforeexpand" : true,
34406 * @event beforecollapse
34407 * Fires before a node is collapsed, return false to cancel.
34408 * @param {Node} node The node
34409 * @param {Boolean} deep
34410 * @param {Boolean} anim
34412 "beforecollapse" : true,
34415 * Fires when a node is expanded
34416 * @param {Node} node The node
34420 * @event disabledchange
34421 * Fires when the disabled status of a node changes
34422 * @param {Node} node The node
34423 * @param {Boolean} disabled
34425 "disabledchange" : true,
34428 * Fires when a node is collapsed
34429 * @param {Node} node The node
34433 * @event beforeclick
34434 * Fires before click processing on a node. Return false to cancel the default action.
34435 * @param {Node} node The node
34436 * @param {Roo.EventObject} e The event object
34438 "beforeclick":true,
34440 * @event checkchange
34441 * Fires when a node with a checkbox's checked property changes
34442 * @param {Node} this This node
34443 * @param {Boolean} checked
34445 "checkchange":true,
34448 * Fires when a node is clicked
34449 * @param {Node} node The node
34450 * @param {Roo.EventObject} e The event object
34455 * Fires when a node is double clicked
34456 * @param {Node} node The node
34457 * @param {Roo.EventObject} e The event object
34461 * @event contextmenu
34462 * Fires when a node is right clicked
34463 * @param {Node} node The node
34464 * @param {Roo.EventObject} e The event object
34466 "contextmenu":true,
34468 * @event beforechildrenrendered
34469 * Fires right before the child nodes for a node are rendered
34470 * @param {Node} node The node
34472 "beforechildrenrendered":true,
34475 * Fires when a node starts being dragged
34476 * @param {Roo.tree.TreePanel} this
34477 * @param {Roo.tree.TreeNode} node
34478 * @param {event} e The raw browser event
34480 "startdrag" : true,
34483 * Fires when a drag operation is complete
34484 * @param {Roo.tree.TreePanel} this
34485 * @param {Roo.tree.TreeNode} node
34486 * @param {event} e The raw browser event
34491 * Fires when a dragged node is dropped on a valid DD target
34492 * @param {Roo.tree.TreePanel} this
34493 * @param {Roo.tree.TreeNode} node
34494 * @param {DD} dd The dd it was dropped on
34495 * @param {event} e The raw browser event
34499 * @event beforenodedrop
34500 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
34501 * passed to handlers has the following properties:<br />
34502 * <ul style="padding:5px;padding-left:16px;">
34503 * <li>tree - The TreePanel</li>
34504 * <li>target - The node being targeted for the drop</li>
34505 * <li>data - The drag data from the drag source</li>
34506 * <li>point - The point of the drop - append, above or below</li>
34507 * <li>source - The drag source</li>
34508 * <li>rawEvent - Raw mouse event</li>
34509 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
34510 * to be inserted by setting them on this object.</li>
34511 * <li>cancel - Set this to true to cancel the drop.</li>
34513 * @param {Object} dropEvent
34515 "beforenodedrop" : true,
34518 * Fires after a DD object is dropped on a node in this tree. The dropEvent
34519 * passed to handlers has the following properties:<br />
34520 * <ul style="padding:5px;padding-left:16px;">
34521 * <li>tree - The TreePanel</li>
34522 * <li>target - The node being targeted for the drop</li>
34523 * <li>data - The drag data from the drag source</li>
34524 * <li>point - The point of the drop - append, above or below</li>
34525 * <li>source - The drag source</li>
34526 * <li>rawEvent - Raw mouse event</li>
34527 * <li>dropNode - Dropped node(s).</li>
34529 * @param {Object} dropEvent
34533 * @event nodedragover
34534 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
34535 * passed to handlers has the following properties:<br />
34536 * <ul style="padding:5px;padding-left:16px;">
34537 * <li>tree - The TreePanel</li>
34538 * <li>target - The node being targeted for the drop</li>
34539 * <li>data - The drag data from the drag source</li>
34540 * <li>point - The point of the drop - append, above or below</li>
34541 * <li>source - The drag source</li>
34542 * <li>rawEvent - Raw mouse event</li>
34543 * <li>dropNode - Drop node(s) provided by the source.</li>
34544 * <li>cancel - Set this to true to signal drop not allowed.</li>
34546 * @param {Object} dragOverEvent
34548 "nodedragover" : true,
34550 * @event appendnode
34551 * Fires when append node to the tree
34552 * @param {Roo.tree.TreePanel} this
34553 * @param {Roo.tree.TreeNode} node
34554 * @param {Number} index The index of the newly appended node
34556 "appendnode" : true
34559 if(this.singleExpand){
34560 this.on("beforeexpand", this.restrictExpand, this);
34563 this.editor.tree = this;
34564 this.editor = Roo.factory(this.editor, Roo.tree);
34567 if (this.selModel) {
34568 this.selModel = Roo.factory(this.selModel, Roo.tree);
34572 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
34573 rootVisible : true,
34574 animate: Roo.enableFx,
34577 hlDrop : Roo.enableFx,
34581 rendererTip: false,
34583 restrictExpand : function(node){
34584 var p = node.parentNode;
34586 if(p.expandedChild && p.expandedChild.parentNode == p){
34587 p.expandedChild.collapse();
34589 p.expandedChild = node;
34593 // private override
34594 setRootNode : function(node){
34595 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
34596 if(!this.rootVisible){
34597 node.ui = new Roo.tree.RootTreeNodeUI(node);
34603 * Returns the container element for this TreePanel
34605 getEl : function(){
34610 * Returns the default TreeLoader for this TreePanel
34612 getLoader : function(){
34613 return this.loader;
34619 expandAll : function(){
34620 this.root.expand(true);
34624 * Collapse all nodes
34626 collapseAll : function(){
34627 this.root.collapse(true);
34631 * Returns the selection model used by this TreePanel
34633 getSelectionModel : function(){
34634 if(!this.selModel){
34635 this.selModel = new Roo.tree.DefaultSelectionModel();
34637 return this.selModel;
34641 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
34642 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
34643 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
34646 getChecked : function(a, startNode){
34647 startNode = startNode || this.root;
34649 var f = function(){
34650 if(this.attributes.checked){
34651 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
34654 startNode.cascade(f);
34659 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
34660 * @param {String} path
34661 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
34662 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
34663 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
34665 expandPath : function(path, attr, callback){
34666 attr = attr || "id";
34667 var keys = path.split(this.pathSeparator);
34668 var curNode = this.root;
34669 if(curNode.attributes[attr] != keys[1]){ // invalid root
34671 callback(false, null);
34676 var f = function(){
34677 if(++index == keys.length){
34679 callback(true, curNode);
34683 var c = curNode.findChild(attr, keys[index]);
34686 callback(false, curNode);
34691 c.expand(false, false, f);
34693 curNode.expand(false, false, f);
34697 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
34698 * @param {String} path
34699 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
34700 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
34701 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
34703 selectPath : function(path, attr, callback){
34704 attr = attr || "id";
34705 var keys = path.split(this.pathSeparator);
34706 var v = keys.pop();
34707 if(keys.length > 0){
34708 var f = function(success, node){
34709 if(success && node){
34710 var n = node.findChild(attr, v);
34716 }else if(callback){
34717 callback(false, n);
34721 callback(false, n);
34725 this.expandPath(keys.join(this.pathSeparator), attr, f);
34727 this.root.select();
34729 callback(true, this.root);
34734 getTreeEl : function(){
34739 * Trigger rendering of this TreePanel
34741 render : function(){
34742 if (this.innerCt) {
34743 return this; // stop it rendering more than once!!
34746 this.innerCt = this.el.createChild({tag:"ul",
34747 cls:"x-tree-root-ct " +
34748 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
34750 if(this.containerScroll){
34751 Roo.dd.ScrollManager.register(this.el);
34753 if((this.enableDD || this.enableDrop) && !this.dropZone){
34755 * The dropZone used by this tree if drop is enabled
34756 * @type Roo.tree.TreeDropZone
34758 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
34759 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
34762 if((this.enableDD || this.enableDrag) && !this.dragZone){
34764 * The dragZone used by this tree if drag is enabled
34765 * @type Roo.tree.TreeDragZone
34767 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
34768 ddGroup: this.ddGroup || "TreeDD",
34769 scroll: this.ddScroll
34772 this.getSelectionModel().init(this);
34774 Roo.log("ROOT not set in tree");
34777 this.root.render();
34778 if(!this.rootVisible){
34779 this.root.renderChildren();
34785 * Ext JS Library 1.1.1
34786 * Copyright(c) 2006-2007, Ext JS, LLC.
34788 * Originally Released Under LGPL - original licence link has changed is not relivant.
34791 * <script type="text/javascript">
34796 * @class Roo.tree.DefaultSelectionModel
34797 * @extends Roo.util.Observable
34798 * The default single selection for a TreePanel.
34799 * @param {Object} cfg Configuration
34801 Roo.tree.DefaultSelectionModel = function(cfg){
34802 this.selNode = null;
34808 * @event selectionchange
34809 * Fires when the selected node changes
34810 * @param {DefaultSelectionModel} this
34811 * @param {TreeNode} node the new selection
34813 "selectionchange" : true,
34816 * @event beforeselect
34817 * Fires before the selected node changes, return false to cancel the change
34818 * @param {DefaultSelectionModel} this
34819 * @param {TreeNode} node the new selection
34820 * @param {TreeNode} node the old selection
34822 "beforeselect" : true
34825 Roo.tree.DefaultSelectionModel.superclass.constructor.call(this,cfg);
34828 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
34829 init : function(tree){
34831 tree.getTreeEl().on("keydown", this.onKeyDown, this);
34832 tree.on("click", this.onNodeClick, this);
34835 onNodeClick : function(node, e){
34836 if (e.ctrlKey && this.selNode == node) {
34837 this.unselect(node);
34845 * @param {TreeNode} node The node to select
34846 * @return {TreeNode} The selected node
34848 select : function(node){
34849 var last = this.selNode;
34850 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
34852 last.ui.onSelectedChange(false);
34854 this.selNode = node;
34855 node.ui.onSelectedChange(true);
34856 this.fireEvent("selectionchange", this, node, last);
34863 * @param {TreeNode} node The node to unselect
34865 unselect : function(node){
34866 if(this.selNode == node){
34867 this.clearSelections();
34872 * Clear all selections
34874 clearSelections : function(){
34875 var n = this.selNode;
34877 n.ui.onSelectedChange(false);
34878 this.selNode = null;
34879 this.fireEvent("selectionchange", this, null);
34885 * Get the selected node
34886 * @return {TreeNode} The selected node
34888 getSelectedNode : function(){
34889 return this.selNode;
34893 * Returns true if the node is selected
34894 * @param {TreeNode} node The node to check
34895 * @return {Boolean}
34897 isSelected : function(node){
34898 return this.selNode == node;
34902 * Selects the node above the selected node in the tree, intelligently walking the nodes
34903 * @return TreeNode The new selection
34905 selectPrevious : function(){
34906 var s = this.selNode || this.lastSelNode;
34910 var ps = s.previousSibling;
34912 if(!ps.isExpanded() || ps.childNodes.length < 1){
34913 return this.select(ps);
34915 var lc = ps.lastChild;
34916 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
34919 return this.select(lc);
34921 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
34922 return this.select(s.parentNode);
34928 * Selects the node above the selected node in the tree, intelligently walking the nodes
34929 * @return TreeNode The new selection
34931 selectNext : function(){
34932 var s = this.selNode || this.lastSelNode;
34936 if(s.firstChild && s.isExpanded()){
34937 return this.select(s.firstChild);
34938 }else if(s.nextSibling){
34939 return this.select(s.nextSibling);
34940 }else if(s.parentNode){
34942 s.parentNode.bubble(function(){
34943 if(this.nextSibling){
34944 newS = this.getOwnerTree().selModel.select(this.nextSibling);
34953 onKeyDown : function(e){
34954 var s = this.selNode || this.lastSelNode;
34955 // undesirable, but required
34960 var k = e.getKey();
34968 this.selectPrevious();
34971 e.preventDefault();
34972 if(s.hasChildNodes()){
34973 if(!s.isExpanded()){
34975 }else if(s.firstChild){
34976 this.select(s.firstChild, e);
34981 e.preventDefault();
34982 if(s.hasChildNodes() && s.isExpanded()){
34984 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
34985 this.select(s.parentNode, e);
34993 * @class Roo.tree.MultiSelectionModel
34994 * @extends Roo.util.Observable
34995 * Multi selection for a TreePanel.
34996 * @param {Object} cfg Configuration
34998 Roo.tree.MultiSelectionModel = function(){
34999 this.selNodes = [];
35003 * @event selectionchange
35004 * Fires when the selected nodes change
35005 * @param {MultiSelectionModel} this
35006 * @param {Array} nodes Array of the selected nodes
35008 "selectionchange" : true
35010 Roo.tree.MultiSelectionModel.superclass.constructor.call(this,cfg);
35014 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
35015 init : function(tree){
35017 tree.getTreeEl().on("keydown", this.onKeyDown, this);
35018 tree.on("click", this.onNodeClick, this);
35021 onNodeClick : function(node, e){
35022 this.select(node, e, e.ctrlKey);
35027 * @param {TreeNode} node The node to select
35028 * @param {EventObject} e (optional) An event associated with the selection
35029 * @param {Boolean} keepExisting True to retain existing selections
35030 * @return {TreeNode} The selected node
35032 select : function(node, e, keepExisting){
35033 if(keepExisting !== true){
35034 this.clearSelections(true);
35036 if(this.isSelected(node)){
35037 this.lastSelNode = node;
35040 this.selNodes.push(node);
35041 this.selMap[node.id] = node;
35042 this.lastSelNode = node;
35043 node.ui.onSelectedChange(true);
35044 this.fireEvent("selectionchange", this, this.selNodes);
35050 * @param {TreeNode} node The node to unselect
35052 unselect : function(node){
35053 if(this.selMap[node.id]){
35054 node.ui.onSelectedChange(false);
35055 var sn = this.selNodes;
35058 index = sn.indexOf(node);
35060 for(var i = 0, len = sn.length; i < len; i++){
35068 this.selNodes.splice(index, 1);
35070 delete this.selMap[node.id];
35071 this.fireEvent("selectionchange", this, this.selNodes);
35076 * Clear all selections
35078 clearSelections : function(suppressEvent){
35079 var sn = this.selNodes;
35081 for(var i = 0, len = sn.length; i < len; i++){
35082 sn[i].ui.onSelectedChange(false);
35084 this.selNodes = [];
35086 if(suppressEvent !== true){
35087 this.fireEvent("selectionchange", this, this.selNodes);
35093 * Returns true if the node is selected
35094 * @param {TreeNode} node The node to check
35095 * @return {Boolean}
35097 isSelected : function(node){
35098 return this.selMap[node.id] ? true : false;
35102 * Returns an array of the selected nodes
35105 getSelectedNodes : function(){
35106 return this.selNodes;
35109 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
35111 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
35113 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
35116 * Ext JS Library 1.1.1
35117 * Copyright(c) 2006-2007, Ext JS, LLC.
35119 * Originally Released Under LGPL - original licence link has changed is not relivant.
35122 * <script type="text/javascript">
35126 * @class Roo.tree.TreeNode
35127 * @extends Roo.data.Node
35128 * @cfg {String} text The text for this node
35129 * @cfg {Boolean} expanded true to start the node expanded
35130 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
35131 * @cfg {Boolean} allowDrop false if this node cannot be drop on
35132 * @cfg {Boolean} disabled true to start the node disabled
35133 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
35134 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
35135 * @cfg {String} cls A css class to be added to the node
35136 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
35137 * @cfg {String} href URL of the link used for the node (defaults to #)
35138 * @cfg {String} hrefTarget target frame for the link
35139 * @cfg {String} qtip An Ext QuickTip for the node
35140 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
35141 * @cfg {Boolean} singleClickExpand True for single click expand on this node
35142 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
35143 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
35144 * (defaults to undefined with no checkbox rendered)
35146 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
35148 Roo.tree.TreeNode = function(attributes){
35149 attributes = attributes || {};
35150 if(typeof attributes == "string"){
35151 attributes = {text: attributes};
35153 this.childrenRendered = false;
35154 this.rendered = false;
35155 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
35156 this.expanded = attributes.expanded === true;
35157 this.isTarget = attributes.isTarget !== false;
35158 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
35159 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
35162 * Read-only. The text for this node. To change it use setText().
35165 this.text = attributes.text;
35167 * True if this node is disabled.
35170 this.disabled = attributes.disabled === true;
35174 * @event textchange
35175 * Fires when the text for this node is changed
35176 * @param {Node} this This node
35177 * @param {String} text The new text
35178 * @param {String} oldText The old text
35180 "textchange" : true,
35182 * @event beforeexpand
35183 * Fires before this node is expanded, return false to cancel.
35184 * @param {Node} this This node
35185 * @param {Boolean} deep
35186 * @param {Boolean} anim
35188 "beforeexpand" : true,
35190 * @event beforecollapse
35191 * Fires before this node is collapsed, return false to cancel.
35192 * @param {Node} this This node
35193 * @param {Boolean} deep
35194 * @param {Boolean} anim
35196 "beforecollapse" : true,
35199 * Fires when this node is expanded
35200 * @param {Node} this This node
35204 * @event disabledchange
35205 * Fires when the disabled status of this node changes
35206 * @param {Node} this This node
35207 * @param {Boolean} disabled
35209 "disabledchange" : true,
35212 * Fires when this node is collapsed
35213 * @param {Node} this This node
35217 * @event beforeclick
35218 * Fires before click processing. Return false to cancel the default action.
35219 * @param {Node} this This node
35220 * @param {Roo.EventObject} e The event object
35222 "beforeclick":true,
35224 * @event checkchange
35225 * Fires when a node with a checkbox's checked property changes
35226 * @param {Node} this This node
35227 * @param {Boolean} checked
35229 "checkchange":true,
35232 * Fires when this node is clicked
35233 * @param {Node} this This node
35234 * @param {Roo.EventObject} e The event object
35239 * Fires when this node is double clicked
35240 * @param {Node} this This node
35241 * @param {Roo.EventObject} e The event object
35245 * @event contextmenu
35246 * Fires when this node is right clicked
35247 * @param {Node} this This node
35248 * @param {Roo.EventObject} e The event object
35250 "contextmenu":true,
35252 * @event beforechildrenrendered
35253 * Fires right before the child nodes for this node are rendered
35254 * @param {Node} this This node
35256 "beforechildrenrendered":true
35259 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
35262 * Read-only. The UI for this node
35265 this.ui = new uiClass(this);
35267 // finally support items[]
35268 if (typeof(this.attributes.items) == 'undefined' || !this.attributes.items) {
35273 Roo.each(this.attributes.items, function(c) {
35274 this.appendChild(Roo.factory(c,Roo.Tree));
35276 delete this.attributes.items;
35281 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
35282 preventHScroll: true,
35284 * Returns true if this node is expanded
35285 * @return {Boolean}
35287 isExpanded : function(){
35288 return this.expanded;
35292 * Returns the UI object for this node
35293 * @return {TreeNodeUI}
35295 getUI : function(){
35299 // private override
35300 setFirstChild : function(node){
35301 var of = this.firstChild;
35302 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
35303 if(this.childrenRendered && of && node != of){
35304 of.renderIndent(true, true);
35307 this.renderIndent(true, true);
35311 // private override
35312 setLastChild : function(node){
35313 var ol = this.lastChild;
35314 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
35315 if(this.childrenRendered && ol && node != ol){
35316 ol.renderIndent(true, true);
35319 this.renderIndent(true, true);
35323 // these methods are overridden to provide lazy rendering support
35324 // private override
35325 appendChild : function()
35327 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
35328 if(node && this.childrenRendered){
35331 this.ui.updateExpandIcon();
35335 // private override
35336 removeChild : function(node){
35337 this.ownerTree.getSelectionModel().unselect(node);
35338 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
35339 // if it's been rendered remove dom node
35340 if(this.childrenRendered){
35343 if(this.childNodes.length < 1){
35344 this.collapse(false, false);
35346 this.ui.updateExpandIcon();
35348 if(!this.firstChild) {
35349 this.childrenRendered = false;
35354 // private override
35355 insertBefore : function(node, refNode){
35356 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
35357 if(newNode && refNode && this.childrenRendered){
35360 this.ui.updateExpandIcon();
35365 * Sets the text for this node
35366 * @param {String} text
35368 setText : function(text){
35369 var oldText = this.text;
35371 this.attributes.text = text;
35372 if(this.rendered){ // event without subscribing
35373 this.ui.onTextChange(this, text, oldText);
35375 this.fireEvent("textchange", this, text, oldText);
35379 * Triggers selection of this node
35381 select : function(){
35382 this.getOwnerTree().getSelectionModel().select(this);
35386 * Triggers deselection of this node
35388 unselect : function(){
35389 this.getOwnerTree().getSelectionModel().unselect(this);
35393 * Returns true if this node is selected
35394 * @return {Boolean}
35396 isSelected : function(){
35397 return this.getOwnerTree().getSelectionModel().isSelected(this);
35401 * Expand this node.
35402 * @param {Boolean} deep (optional) True to expand all children as well
35403 * @param {Boolean} anim (optional) false to cancel the default animation
35404 * @param {Function} callback (optional) A callback to be called when
35405 * expanding this node completes (does not wait for deep expand to complete).
35406 * Called with 1 parameter, this node.
35408 expand : function(deep, anim, callback){
35409 if(!this.expanded){
35410 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
35413 if(!this.childrenRendered){
35414 this.renderChildren();
35416 this.expanded = true;
35418 if(!this.isHiddenRoot() && (this.getOwnerTree() && this.getOwnerTree().animate && anim !== false) || anim){
35419 this.ui.animExpand(function(){
35420 this.fireEvent("expand", this);
35421 if(typeof callback == "function"){
35425 this.expandChildNodes(true);
35427 }.createDelegate(this));
35431 this.fireEvent("expand", this);
35432 if(typeof callback == "function"){
35437 if(typeof callback == "function"){
35442 this.expandChildNodes(true);
35446 isHiddenRoot : function(){
35447 return this.isRoot && !this.getOwnerTree().rootVisible;
35451 * Collapse this node.
35452 * @param {Boolean} deep (optional) True to collapse all children as well
35453 * @param {Boolean} anim (optional) false to cancel the default animation
35455 collapse : function(deep, anim){
35456 if(this.expanded && !this.isHiddenRoot()){
35457 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
35460 this.expanded = false;
35461 if((this.getOwnerTree().animate && anim !== false) || anim){
35462 this.ui.animCollapse(function(){
35463 this.fireEvent("collapse", this);
35465 this.collapseChildNodes(true);
35467 }.createDelegate(this));
35470 this.ui.collapse();
35471 this.fireEvent("collapse", this);
35475 var cs = this.childNodes;
35476 for(var i = 0, len = cs.length; i < len; i++) {
35477 cs[i].collapse(true, false);
35483 delayedExpand : function(delay){
35484 if(!this.expandProcId){
35485 this.expandProcId = this.expand.defer(delay, this);
35490 cancelExpand : function(){
35491 if(this.expandProcId){
35492 clearTimeout(this.expandProcId);
35494 this.expandProcId = false;
35498 * Toggles expanded/collapsed state of the node
35500 toggle : function(){
35509 * Ensures all parent nodes are expanded
35511 ensureVisible : function(callback){
35512 var tree = this.getOwnerTree();
35513 tree.expandPath(this.parentNode.getPath(), false, function(){
35514 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
35515 Roo.callback(callback);
35516 }.createDelegate(this));
35520 * Expand all child nodes
35521 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
35523 expandChildNodes : function(deep){
35524 var cs = this.childNodes;
35525 for(var i = 0, len = cs.length; i < len; i++) {
35526 cs[i].expand(deep);
35531 * Collapse all child nodes
35532 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
35534 collapseChildNodes : function(deep){
35535 var cs = this.childNodes;
35536 for(var i = 0, len = cs.length; i < len; i++) {
35537 cs[i].collapse(deep);
35542 * Disables this node
35544 disable : function(){
35545 this.disabled = true;
35547 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
35548 this.ui.onDisableChange(this, true);
35550 this.fireEvent("disabledchange", this, true);
35554 * Enables this node
35556 enable : function(){
35557 this.disabled = false;
35558 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
35559 this.ui.onDisableChange(this, false);
35561 this.fireEvent("disabledchange", this, false);
35565 renderChildren : function(suppressEvent){
35566 if(suppressEvent !== false){
35567 this.fireEvent("beforechildrenrendered", this);
35569 var cs = this.childNodes;
35570 for(var i = 0, len = cs.length; i < len; i++){
35571 cs[i].render(true);
35573 this.childrenRendered = true;
35577 sort : function(fn, scope){
35578 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
35579 if(this.childrenRendered){
35580 var cs = this.childNodes;
35581 for(var i = 0, len = cs.length; i < len; i++){
35582 cs[i].render(true);
35588 render : function(bulkRender){
35589 this.ui.render(bulkRender);
35590 if(!this.rendered){
35591 this.rendered = true;
35593 this.expanded = false;
35594 this.expand(false, false);
35600 renderIndent : function(deep, refresh){
35602 this.ui.childIndent = null;
35604 this.ui.renderIndent();
35605 if(deep === true && this.childrenRendered){
35606 var cs = this.childNodes;
35607 for(var i = 0, len = cs.length; i < len; i++){
35608 cs[i].renderIndent(true, refresh);
35614 * Ext JS Library 1.1.1
35615 * Copyright(c) 2006-2007, Ext JS, LLC.
35617 * Originally Released Under LGPL - original licence link has changed is not relivant.
35620 * <script type="text/javascript">
35624 * @class Roo.tree.AsyncTreeNode
35625 * @extends Roo.tree.TreeNode
35626 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
35628 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
35630 Roo.tree.AsyncTreeNode = function(config){
35631 this.loaded = false;
35632 this.loading = false;
35633 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
35635 * @event beforeload
35636 * Fires before this node is loaded, return false to cancel
35637 * @param {Node} this This node
35639 this.addEvents({'beforeload':true, 'load': true});
35642 * Fires when this node is loaded
35643 * @param {Node} this This node
35646 * The loader used by this node (defaults to using the tree's defined loader)
35651 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
35652 expand : function(deep, anim, callback){
35653 if(this.loading){ // if an async load is already running, waiting til it's done
35655 var f = function(){
35656 if(!this.loading){ // done loading
35657 clearInterval(timer);
35658 this.expand(deep, anim, callback);
35660 }.createDelegate(this);
35661 timer = setInterval(f, 200);
35665 if(this.fireEvent("beforeload", this) === false){
35668 this.loading = true;
35669 this.ui.beforeLoad(this);
35670 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
35672 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
35676 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
35680 * Returns true if this node is currently loading
35681 * @return {Boolean}
35683 isLoading : function(){
35684 return this.loading;
35687 loadComplete : function(deep, anim, callback){
35688 this.loading = false;
35689 this.loaded = true;
35690 this.ui.afterLoad(this);
35691 this.fireEvent("load", this);
35692 this.expand(deep, anim, callback);
35696 * Returns true if this node has been loaded
35697 * @return {Boolean}
35699 isLoaded : function(){
35700 return this.loaded;
35703 hasChildNodes : function(){
35704 if(!this.isLeaf() && !this.loaded){
35707 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
35712 * Trigger a reload for this node
35713 * @param {Function} callback
35715 reload : function(callback){
35716 this.collapse(false, false);
35717 while(this.firstChild){
35718 this.removeChild(this.firstChild);
35720 this.childrenRendered = false;
35721 this.loaded = false;
35722 if(this.isHiddenRoot()){
35723 this.expanded = false;
35725 this.expand(false, false, callback);
35729 * Ext JS Library 1.1.1
35730 * Copyright(c) 2006-2007, Ext JS, LLC.
35732 * Originally Released Under LGPL - original licence link has changed is not relivant.
35735 * <script type="text/javascript">
35739 * @class Roo.tree.TreeNodeUI
35741 * @param {Object} node The node to render
35742 * The TreeNode UI implementation is separate from the
35743 * tree implementation. Unless you are customizing the tree UI,
35744 * you should never have to use this directly.
35746 Roo.tree.TreeNodeUI = function(node){
35748 this.rendered = false;
35749 this.animating = false;
35750 this.emptyIcon = Roo.BLANK_IMAGE_URL;
35753 Roo.tree.TreeNodeUI.prototype = {
35754 removeChild : function(node){
35756 this.ctNode.removeChild(node.ui.getEl());
35760 beforeLoad : function(){
35761 this.addClass("x-tree-node-loading");
35764 afterLoad : function(){
35765 this.removeClass("x-tree-node-loading");
35768 onTextChange : function(node, text, oldText){
35770 this.textNode.innerHTML = text;
35774 onDisableChange : function(node, state){
35775 this.disabled = state;
35777 this.addClass("x-tree-node-disabled");
35779 this.removeClass("x-tree-node-disabled");
35783 onSelectedChange : function(state){
35786 this.addClass("x-tree-selected");
35789 this.removeClass("x-tree-selected");
35793 onMove : function(tree, node, oldParent, newParent, index, refNode){
35794 this.childIndent = null;
35796 var targetNode = newParent.ui.getContainer();
35797 if(!targetNode){//target not rendered
35798 this.holder = document.createElement("div");
35799 this.holder.appendChild(this.wrap);
35802 var insertBefore = refNode ? refNode.ui.getEl() : null;
35804 targetNode.insertBefore(this.wrap, insertBefore);
35806 targetNode.appendChild(this.wrap);
35808 this.node.renderIndent(true);
35812 addClass : function(cls){
35814 Roo.fly(this.elNode).addClass(cls);
35818 removeClass : function(cls){
35820 Roo.fly(this.elNode).removeClass(cls);
35824 remove : function(){
35826 this.holder = document.createElement("div");
35827 this.holder.appendChild(this.wrap);
35831 fireEvent : function(){
35832 return this.node.fireEvent.apply(this.node, arguments);
35835 initEvents : function(){
35836 this.node.on("move", this.onMove, this);
35837 var E = Roo.EventManager;
35838 var a = this.anchor;
35840 var el = Roo.fly(a, '_treeui');
35842 if(Roo.isOpera){ // opera render bug ignores the CSS
35843 el.setStyle("text-decoration", "none");
35846 el.on("click", this.onClick, this);
35847 el.on("dblclick", this.onDblClick, this);
35850 Roo.EventManager.on(this.checkbox,
35851 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
35854 el.on("contextmenu", this.onContextMenu, this);
35856 var icon = Roo.fly(this.iconNode);
35857 icon.on("click", this.onClick, this);
35858 icon.on("dblclick", this.onDblClick, this);
35859 icon.on("contextmenu", this.onContextMenu, this);
35860 E.on(this.ecNode, "click", this.ecClick, this, true);
35862 if(this.node.disabled){
35863 this.addClass("x-tree-node-disabled");
35865 if(this.node.hidden){
35866 this.addClass("x-tree-node-disabled");
35868 var ot = this.node.getOwnerTree();
35869 var dd = ot ? (ot.enableDD || ot.enableDrag || ot.enableDrop) : false;
35870 if(dd && (!this.node.isRoot || ot.rootVisible)){
35871 Roo.dd.Registry.register(this.elNode, {
35873 handles: this.getDDHandles(),
35879 getDDHandles : function(){
35880 return [this.iconNode, this.textNode];
35885 this.wrap.style.display = "none";
35891 this.wrap.style.display = "";
35895 onContextMenu : function(e){
35896 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
35897 e.preventDefault();
35899 this.fireEvent("contextmenu", this.node, e);
35903 onClick : function(e){
35908 if(this.fireEvent("beforeclick", this.node, e) !== false){
35909 if(!this.disabled && this.node.attributes.href){
35910 this.fireEvent("click", this.node, e);
35913 e.preventDefault();
35918 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
35919 this.node.toggle();
35922 this.fireEvent("click", this.node, e);
35928 onDblClick : function(e){
35929 e.preventDefault();
35934 this.toggleCheck();
35936 if(!this.animating && this.node.hasChildNodes()){
35937 this.node.toggle();
35939 this.fireEvent("dblclick", this.node, e);
35942 onCheckChange : function(){
35943 var checked = this.checkbox.checked;
35944 this.node.attributes.checked = checked;
35945 this.fireEvent('checkchange', this.node, checked);
35948 ecClick : function(e){
35949 if(!this.animating && this.node.hasChildNodes()){
35950 this.node.toggle();
35954 startDrop : function(){
35955 this.dropping = true;
35958 // delayed drop so the click event doesn't get fired on a drop
35959 endDrop : function(){
35960 setTimeout(function(){
35961 this.dropping = false;
35962 }.createDelegate(this), 50);
35965 expand : function(){
35966 this.updateExpandIcon();
35967 this.ctNode.style.display = "";
35970 focus : function(){
35971 if(!this.node.preventHScroll){
35972 try{this.anchor.focus();
35974 }else if(!Roo.isIE){
35976 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
35977 var l = noscroll.scrollLeft;
35978 this.anchor.focus();
35979 noscroll.scrollLeft = l;
35984 toggleCheck : function(value){
35985 var cb = this.checkbox;
35987 cb.checked = (value === undefined ? !cb.checked : value);
35993 this.anchor.blur();
35997 animExpand : function(callback){
35998 var ct = Roo.get(this.ctNode);
36000 if(!this.node.hasChildNodes()){
36001 this.updateExpandIcon();
36002 this.ctNode.style.display = "";
36003 Roo.callback(callback);
36006 this.animating = true;
36007 this.updateExpandIcon();
36010 callback : function(){
36011 this.animating = false;
36012 Roo.callback(callback);
36015 duration: this.node.ownerTree.duration || .25
36019 highlight : function(){
36020 var tree = this.node.getOwnerTree();
36021 Roo.fly(this.wrap).highlight(
36022 tree.hlColor || "C3DAF9",
36023 {endColor: tree.hlBaseColor}
36027 collapse : function(){
36028 this.updateExpandIcon();
36029 this.ctNode.style.display = "none";
36032 animCollapse : function(callback){
36033 var ct = Roo.get(this.ctNode);
36034 ct.enableDisplayMode('block');
36037 this.animating = true;
36038 this.updateExpandIcon();
36041 callback : function(){
36042 this.animating = false;
36043 Roo.callback(callback);
36046 duration: this.node.ownerTree.duration || .25
36050 getContainer : function(){
36051 return this.ctNode;
36054 getEl : function(){
36058 appendDDGhost : function(ghostNode){
36059 ghostNode.appendChild(this.elNode.cloneNode(true));
36062 getDDRepairXY : function(){
36063 return Roo.lib.Dom.getXY(this.iconNode);
36066 onRender : function(){
36070 render : function(bulkRender){
36071 var n = this.node, a = n.attributes;
36072 var targetNode = n.parentNode ?
36073 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
36075 if(!this.rendered){
36076 this.rendered = true;
36078 this.renderElements(n, a, targetNode, bulkRender);
36081 if(this.textNode.setAttributeNS){
36082 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
36084 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
36087 this.textNode.setAttribute("ext:qtip", a.qtip);
36089 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
36092 }else if(a.qtipCfg){
36093 a.qtipCfg.target = Roo.id(this.textNode);
36094 Roo.QuickTips.register(a.qtipCfg);
36097 if(!this.node.expanded){
36098 this.updateExpandIcon();
36101 if(bulkRender === true) {
36102 targetNode.appendChild(this.wrap);
36107 renderElements : function(n, a, targetNode, bulkRender)
36109 // add some indent caching, this helps performance when rendering a large tree
36110 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
36111 var t = n.getOwnerTree();
36112 var txt = t && t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
36113 if (typeof(n.attributes.html) != 'undefined') {
36114 txt = n.attributes.html;
36116 var tip = t && t.rendererTip ? t.rendererTip(n.attributes) : txt;
36117 var cb = typeof a.checked == 'boolean';
36118 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
36119 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
36120 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
36121 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
36122 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
36123 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
36124 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
36125 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
36126 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
36127 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
36130 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
36131 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
36132 n.nextSibling.ui.getEl(), buf.join(""));
36134 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
36137 this.elNode = this.wrap.childNodes[0];
36138 this.ctNode = this.wrap.childNodes[1];
36139 var cs = this.elNode.childNodes;
36140 this.indentNode = cs[0];
36141 this.ecNode = cs[1];
36142 this.iconNode = cs[2];
36145 this.checkbox = cs[3];
36148 this.anchor = cs[index];
36149 this.textNode = cs[index].firstChild;
36152 getAnchor : function(){
36153 return this.anchor;
36156 getTextEl : function(){
36157 return this.textNode;
36160 getIconEl : function(){
36161 return this.iconNode;
36164 isChecked : function(){
36165 return this.checkbox ? this.checkbox.checked : false;
36168 updateExpandIcon : function(){
36170 var n = this.node, c1, c2;
36171 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
36172 var hasChild = n.hasChildNodes();
36176 c1 = "x-tree-node-collapsed";
36177 c2 = "x-tree-node-expanded";
36180 c1 = "x-tree-node-expanded";
36181 c2 = "x-tree-node-collapsed";
36184 this.removeClass("x-tree-node-leaf");
36185 this.wasLeaf = false;
36187 if(this.c1 != c1 || this.c2 != c2){
36188 Roo.fly(this.elNode).replaceClass(c1, c2);
36189 this.c1 = c1; this.c2 = c2;
36192 // this changes non-leafs into leafs if they have no children.
36193 // it's not very rational behaviour..
36195 if(!this.wasLeaf && this.node.leaf){
36196 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
36199 this.wasLeaf = true;
36202 var ecc = "x-tree-ec-icon "+cls;
36203 if(this.ecc != ecc){
36204 this.ecNode.className = ecc;
36210 getChildIndent : function(){
36211 if(!this.childIndent){
36215 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
36217 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
36219 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
36224 this.childIndent = buf.join("");
36226 return this.childIndent;
36229 renderIndent : function(){
36232 var p = this.node.parentNode;
36234 indent = p.ui.getChildIndent();
36236 if(this.indentMarkup != indent){ // don't rerender if not required
36237 this.indentNode.innerHTML = indent;
36238 this.indentMarkup = indent;
36240 this.updateExpandIcon();
36245 Roo.tree.RootTreeNodeUI = function(){
36246 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
36248 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
36249 render : function(){
36250 if(!this.rendered){
36251 var targetNode = this.node.ownerTree.innerCt.dom;
36252 this.node.expanded = true;
36253 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
36254 this.wrap = this.ctNode = targetNode.firstChild;
36257 collapse : function(){
36259 expand : function(){
36263 * Ext JS Library 1.1.1
36264 * Copyright(c) 2006-2007, Ext JS, LLC.
36266 * Originally Released Under LGPL - original licence link has changed is not relivant.
36269 * <script type="text/javascript">
36272 * @class Roo.tree.TreeLoader
36273 * @extends Roo.util.Observable
36274 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
36275 * nodes from a specified URL. The response must be a javascript Array definition
36276 * who's elements are node definition objects. eg:
36281 { 'id': 1, 'text': 'A folder Node', 'leaf': false },
36282 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }
36289 * The old style respose with just an array is still supported, but not recommended.
36292 * A server request is sent, and child nodes are loaded only when a node is expanded.
36293 * The loading node's id is passed to the server under the parameter name "node" to
36294 * enable the server to produce the correct child nodes.
36296 * To pass extra parameters, an event handler may be attached to the "beforeload"
36297 * event, and the parameters specified in the TreeLoader's baseParams property:
36299 myTreeLoader.on("beforeload", function(treeLoader, node) {
36300 this.baseParams.category = node.attributes.category;
36305 * This would pass an HTTP parameter called "category" to the server containing
36306 * the value of the Node's "category" attribute.
36308 * Creates a new Treeloader.
36309 * @param {Object} config A config object containing config properties.
36311 Roo.tree.TreeLoader = function(config){
36312 this.baseParams = {};
36313 this.requestMethod = "POST";
36314 Roo.apply(this, config);
36319 * @event beforeload
36320 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
36321 * @param {Object} This TreeLoader object.
36322 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
36323 * @param {Object} callback The callback function specified in the {@link #load} call.
36328 * Fires when the node has been successfuly loaded.
36329 * @param {Object} This TreeLoader object.
36330 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
36331 * @param {Object} response The response object containing the data from the server.
36335 * @event loadexception
36336 * Fires if the network request failed.
36337 * @param {Object} This TreeLoader object.
36338 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
36339 * @param {Object} response The response object containing the data from the server.
36341 loadexception : true,
36344 * Fires before a node is created, enabling you to return custom Node types
36345 * @param {Object} This TreeLoader object.
36346 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
36351 Roo.tree.TreeLoader.superclass.constructor.call(this);
36354 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
36356 * @cfg {String} dataUrl The URL from which to request a Json string which
36357 * specifies an array of node definition object representing the child nodes
36361 * @cfg {String} requestMethod either GET or POST
36362 * defaults to POST (due to BC)
36366 * @cfg {Object} baseParams (optional) An object containing properties which
36367 * specify HTTP parameters to be passed to each request for child nodes.
36370 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
36371 * created by this loader. If the attributes sent by the server have an attribute in this object,
36372 * they take priority.
36375 * @cfg {Object} uiProviders (optional) An object containing properties which
36377 * DEPRECATED - use 'create' event handler to modify attributes - which affect creation.
36378 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
36379 * <i>uiProvider</i> attribute of a returned child node is a string rather
36380 * than a reference to a TreeNodeUI implementation, this that string value
36381 * is used as a property name in the uiProviders object. You can define the provider named
36382 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
36387 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
36388 * child nodes before loading.
36390 clearOnLoad : true,
36393 * @cfg {String} root (optional) Default to false. Use this to read data from an object
36394 * property on loading, rather than expecting an array. (eg. more compatible to a standard
36395 * Grid query { data : [ .....] }
36400 * @cfg {String} queryParam (optional)
36401 * Name of the query as it will be passed on the querystring (defaults to 'node')
36402 * eg. the request will be ?node=[id]
36409 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
36410 * This is called automatically when a node is expanded, but may be used to reload
36411 * a node (or append new children if the {@link #clearOnLoad} option is false.)
36412 * @param {Roo.tree.TreeNode} node
36413 * @param {Function} callback
36415 load : function(node, callback){
36416 if(this.clearOnLoad){
36417 while(node.firstChild){
36418 node.removeChild(node.firstChild);
36421 if(node.attributes.children){ // preloaded json children
36422 var cs = node.attributes.children;
36423 for(var i = 0, len = cs.length; i < len; i++){
36424 node.appendChild(this.createNode(cs[i]));
36426 if(typeof callback == "function"){
36429 }else if(this.dataUrl){
36430 this.requestData(node, callback);
36434 getParams: function(node){
36435 var buf = [], bp = this.baseParams;
36436 for(var key in bp){
36437 if(typeof bp[key] != "function"){
36438 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
36441 var n = this.queryParam === false ? 'node' : this.queryParam;
36442 buf.push(n + "=", encodeURIComponent(node.id));
36443 return buf.join("");
36446 requestData : function(node, callback){
36447 if(this.fireEvent("beforeload", this, node, callback) !== false){
36448 this.transId = Roo.Ajax.request({
36449 method:this.requestMethod,
36450 url: this.dataUrl||this.url,
36451 success: this.handleResponse,
36452 failure: this.handleFailure,
36454 argument: {callback: callback, node: node},
36455 params: this.getParams(node)
36458 // if the load is cancelled, make sure we notify
36459 // the node that we are done
36460 if(typeof callback == "function"){
36466 isLoading : function(){
36467 return this.transId ? true : false;
36470 abort : function(){
36471 if(this.isLoading()){
36472 Roo.Ajax.abort(this.transId);
36477 createNode : function(attr)
36479 // apply baseAttrs, nice idea Corey!
36480 if(this.baseAttrs){
36481 Roo.applyIf(attr, this.baseAttrs);
36483 if(this.applyLoader !== false){
36484 attr.loader = this;
36486 // uiProvider = depreciated..
36488 if(typeof(attr.uiProvider) == 'string'){
36489 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
36490 /** eval:var:attr */ eval(attr.uiProvider);
36492 if(typeof(this.uiProviders['default']) != 'undefined') {
36493 attr.uiProvider = this.uiProviders['default'];
36496 this.fireEvent('create', this, attr);
36498 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
36500 new Roo.tree.TreeNode(attr) :
36501 new Roo.tree.AsyncTreeNode(attr));
36504 processResponse : function(response, node, callback)
36506 var json = response.responseText;
36509 var o = Roo.decode(json);
36511 if (this.root === false && typeof(o.success) != undefined) {
36512 this.root = 'data'; // the default behaviour for list like data..
36515 if (this.root !== false && !o.success) {
36516 // it's a failure condition.
36517 var a = response.argument;
36518 this.fireEvent("loadexception", this, a.node, response);
36519 Roo.log("Load failed - should have a handler really");
36525 if (this.root !== false) {
36529 for(var i = 0, len = o.length; i < len; i++){
36530 var n = this.createNode(o[i]);
36532 node.appendChild(n);
36535 if(typeof callback == "function"){
36536 callback(this, node);
36539 this.handleFailure(response);
36543 handleResponse : function(response){
36544 this.transId = false;
36545 var a = response.argument;
36546 this.processResponse(response, a.node, a.callback);
36547 this.fireEvent("load", this, a.node, response);
36550 handleFailure : function(response)
36552 // should handle failure better..
36553 this.transId = false;
36554 var a = response.argument;
36555 this.fireEvent("loadexception", this, a.node, response);
36556 if(typeof a.callback == "function"){
36557 a.callback(this, a.node);
36562 * Ext JS Library 1.1.1
36563 * Copyright(c) 2006-2007, Ext JS, LLC.
36565 * Originally Released Under LGPL - original licence link has changed is not relivant.
36568 * <script type="text/javascript">
36572 * @class Roo.tree.TreeFilter
36573 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
36574 * @param {TreePanel} tree
36575 * @param {Object} config (optional)
36577 Roo.tree.TreeFilter = function(tree, config){
36579 this.filtered = {};
36580 Roo.apply(this, config);
36583 Roo.tree.TreeFilter.prototype = {
36590 * Filter the data by a specific attribute.
36591 * @param {String/RegExp} value Either string that the attribute value
36592 * should start with or a RegExp to test against the attribute
36593 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
36594 * @param {TreeNode} startNode (optional) The node to start the filter at.
36596 filter : function(value, attr, startNode){
36597 attr = attr || "text";
36599 if(typeof value == "string"){
36600 var vlen = value.length;
36601 // auto clear empty filter
36602 if(vlen == 0 && this.clearBlank){
36606 value = value.toLowerCase();
36608 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
36610 }else if(value.exec){ // regex?
36612 return value.test(n.attributes[attr]);
36615 throw 'Illegal filter type, must be string or regex';
36617 this.filterBy(f, null, startNode);
36621 * Filter by a function. The passed function will be called with each
36622 * node in the tree (or from the startNode). If the function returns true, the node is kept
36623 * otherwise it is filtered. If a node is filtered, its children are also filtered.
36624 * @param {Function} fn The filter function
36625 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
36627 filterBy : function(fn, scope, startNode){
36628 startNode = startNode || this.tree.root;
36629 if(this.autoClear){
36632 var af = this.filtered, rv = this.reverse;
36633 var f = function(n){
36634 if(n == startNode){
36640 var m = fn.call(scope || n, n);
36648 startNode.cascade(f);
36651 if(typeof id != "function"){
36653 if(n && n.parentNode){
36654 n.parentNode.removeChild(n);
36662 * Clears the current filter. Note: with the "remove" option
36663 * set a filter cannot be cleared.
36665 clear : function(){
36667 var af = this.filtered;
36669 if(typeof id != "function"){
36676 this.filtered = {};
36681 * Ext JS Library 1.1.1
36682 * Copyright(c) 2006-2007, Ext JS, LLC.
36684 * Originally Released Under LGPL - original licence link has changed is not relivant.
36687 * <script type="text/javascript">
36692 * @class Roo.tree.TreeSorter
36693 * Provides sorting of nodes in a TreePanel
36695 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
36696 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
36697 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
36698 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
36699 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
36700 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
36702 * @param {TreePanel} tree
36703 * @param {Object} config
36705 Roo.tree.TreeSorter = function(tree, config){
36706 Roo.apply(this, config);
36707 tree.on("beforechildrenrendered", this.doSort, this);
36708 tree.on("append", this.updateSort, this);
36709 tree.on("insert", this.updateSort, this);
36711 var dsc = this.dir && this.dir.toLowerCase() == "desc";
36712 var p = this.property || "text";
36713 var sortType = this.sortType;
36714 var fs = this.folderSort;
36715 var cs = this.caseSensitive === true;
36716 var leafAttr = this.leafAttr || 'leaf';
36718 this.sortFn = function(n1, n2){
36720 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
36723 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
36727 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
36728 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
36730 return dsc ? +1 : -1;
36732 return dsc ? -1 : +1;
36739 Roo.tree.TreeSorter.prototype = {
36740 doSort : function(node){
36741 node.sort(this.sortFn);
36744 compareNodes : function(n1, n2){
36745 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
36748 updateSort : function(tree, node){
36749 if(node.childrenRendered){
36750 this.doSort.defer(1, this, [node]);
36755 * Ext JS Library 1.1.1
36756 * Copyright(c) 2006-2007, Ext JS, LLC.
36758 * Originally Released Under LGPL - original licence link has changed is not relivant.
36761 * <script type="text/javascript">
36764 if(Roo.dd.DropZone){
36766 Roo.tree.TreeDropZone = function(tree, config){
36767 this.allowParentInsert = false;
36768 this.allowContainerDrop = false;
36769 this.appendOnly = false;
36770 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
36772 this.lastInsertClass = "x-tree-no-status";
36773 this.dragOverData = {};
36776 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
36777 ddGroup : "TreeDD",
36780 expandDelay : 1000,
36782 expandNode : function(node){
36783 if(node.hasChildNodes() && !node.isExpanded()){
36784 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
36788 queueExpand : function(node){
36789 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
36792 cancelExpand : function(){
36793 if(this.expandProcId){
36794 clearTimeout(this.expandProcId);
36795 this.expandProcId = false;
36799 isValidDropPoint : function(n, pt, dd, e, data){
36800 if(!n || !data){ return false; }
36801 var targetNode = n.node;
36802 var dropNode = data.node;
36803 // default drop rules
36804 if(!(targetNode && targetNode.isTarget && pt)){
36807 if(pt == "append" && targetNode.allowChildren === false){
36810 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
36813 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
36816 // reuse the object
36817 var overEvent = this.dragOverData;
36818 overEvent.tree = this.tree;
36819 overEvent.target = targetNode;
36820 overEvent.data = data;
36821 overEvent.point = pt;
36822 overEvent.source = dd;
36823 overEvent.rawEvent = e;
36824 overEvent.dropNode = dropNode;
36825 overEvent.cancel = false;
36826 var result = this.tree.fireEvent("nodedragover", overEvent);
36827 return overEvent.cancel === false && result !== false;
36830 getDropPoint : function(e, n, dd)
36834 return tn.allowChildren !== false ? "append" : false; // always append for root
36836 var dragEl = n.ddel;
36837 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
36838 var y = Roo.lib.Event.getPageY(e);
36839 //var noAppend = tn.allowChildren === false || tn.isLeaf();
36841 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
36842 var noAppend = tn.allowChildren === false;
36843 if(this.appendOnly || tn.parentNode.allowChildren === false){
36844 return noAppend ? false : "append";
36846 var noBelow = false;
36847 if(!this.allowParentInsert){
36848 noBelow = tn.hasChildNodes() && tn.isExpanded();
36850 var q = (b - t) / (noAppend ? 2 : 3);
36851 if(y >= t && y < (t + q)){
36853 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
36860 onNodeEnter : function(n, dd, e, data)
36862 this.cancelExpand();
36865 onNodeOver : function(n, dd, e, data)
36868 var pt = this.getDropPoint(e, n, dd);
36871 // auto node expand check
36872 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
36873 this.queueExpand(node);
36874 }else if(pt != "append"){
36875 this.cancelExpand();
36878 // set the insert point style on the target node
36879 var returnCls = this.dropNotAllowed;
36880 if(this.isValidDropPoint(n, pt, dd, e, data)){
36885 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
36886 cls = "x-tree-drag-insert-above";
36887 }else if(pt == "below"){
36888 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
36889 cls = "x-tree-drag-insert-below";
36891 returnCls = "x-tree-drop-ok-append";
36892 cls = "x-tree-drag-append";
36894 if(this.lastInsertClass != cls){
36895 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
36896 this.lastInsertClass = cls;
36903 onNodeOut : function(n, dd, e, data){
36905 this.cancelExpand();
36906 this.removeDropIndicators(n);
36909 onNodeDrop : function(n, dd, e, data){
36910 var point = this.getDropPoint(e, n, dd);
36911 var targetNode = n.node;
36912 targetNode.ui.startDrop();
36913 if(!this.isValidDropPoint(n, point, dd, e, data)){
36914 targetNode.ui.endDrop();
36917 // first try to find the drop node
36918 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
36921 target: targetNode,
36926 dropNode: dropNode,
36929 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
36930 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
36931 targetNode.ui.endDrop();
36934 // allow target changing
36935 targetNode = dropEvent.target;
36936 if(point == "append" && !targetNode.isExpanded()){
36937 targetNode.expand(false, null, function(){
36938 this.completeDrop(dropEvent);
36939 }.createDelegate(this));
36941 this.completeDrop(dropEvent);
36946 completeDrop : function(de){
36947 var ns = de.dropNode, p = de.point, t = de.target;
36948 if(!(ns instanceof Array)){
36952 for(var i = 0, len = ns.length; i < len; i++){
36955 t.parentNode.insertBefore(n, t);
36956 }else if(p == "below"){
36957 t.parentNode.insertBefore(n, t.nextSibling);
36963 if(this.tree.hlDrop){
36967 this.tree.fireEvent("nodedrop", de);
36970 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
36971 if(this.tree.hlDrop){
36972 dropNode.ui.focus();
36973 dropNode.ui.highlight();
36975 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
36978 getTree : function(){
36982 removeDropIndicators : function(n){
36985 Roo.fly(el).removeClass([
36986 "x-tree-drag-insert-above",
36987 "x-tree-drag-insert-below",
36988 "x-tree-drag-append"]);
36989 this.lastInsertClass = "_noclass";
36993 beforeDragDrop : function(target, e, id){
36994 this.cancelExpand();
36998 afterRepair : function(data){
36999 if(data && Roo.enableFx){
37000 data.node.ui.highlight();
37010 * Ext JS Library 1.1.1
37011 * Copyright(c) 2006-2007, Ext JS, LLC.
37013 * Originally Released Under LGPL - original licence link has changed is not relivant.
37016 * <script type="text/javascript">
37020 if(Roo.dd.DragZone){
37021 Roo.tree.TreeDragZone = function(tree, config){
37022 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
37026 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
37027 ddGroup : "TreeDD",
37029 onBeforeDrag : function(data, e){
37031 return n && n.draggable && !n.disabled;
37035 onInitDrag : function(e){
37036 var data = this.dragData;
37037 this.tree.getSelectionModel().select(data.node);
37038 this.proxy.update("");
37039 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
37040 this.tree.fireEvent("startdrag", this.tree, data.node, e);
37043 getRepairXY : function(e, data){
37044 return data.node.ui.getDDRepairXY();
37047 onEndDrag : function(data, e){
37048 this.tree.fireEvent("enddrag", this.tree, data.node, e);
37053 onValidDrop : function(dd, e, id){
37054 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
37058 beforeInvalidDrop : function(e, id){
37059 // this scrolls the original position back into view
37060 var sm = this.tree.getSelectionModel();
37061 sm.clearSelections();
37062 sm.select(this.dragData.node);
37067 * Ext JS Library 1.1.1
37068 * Copyright(c) 2006-2007, Ext JS, LLC.
37070 * Originally Released Under LGPL - original licence link has changed is not relivant.
37073 * <script type="text/javascript">
37076 * @class Roo.tree.TreeEditor
37077 * @extends Roo.Editor
37078 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
37079 * as the editor field.
37081 * @param {Object} config (used to be the tree panel.)
37082 * @param {Object} oldconfig DEPRECIATED Either a prebuilt {@link Roo.form.Field} instance or a Field config object
37084 * @cfg {Roo.tree.TreePanel} tree The tree to bind to.
37085 * @cfg {Roo.form.TextField|Object} field The field configuration
37089 Roo.tree.TreeEditor = function(config, oldconfig) { // was -- (tree, config){
37092 if (oldconfig) { // old style..
37093 field = oldconfig.events ? oldconfig : new Roo.form.TextField(oldconfig);
37096 tree = config.tree;
37097 config.field = config.field || {};
37098 config.field.xtype = 'TextField';
37099 field = Roo.factory(config.field, Roo.form);
37101 config = config || {};
37106 * @event beforenodeedit
37107 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
37108 * false from the handler of this event.
37109 * @param {Editor} this
37110 * @param {Roo.tree.Node} node
37112 "beforenodeedit" : true
37116 Roo.tree.TreeEditor.superclass.constructor.call(this, field, config);
37120 tree.on('beforeclick', this.beforeNodeClick, this);
37121 tree.getTreeEl().on('mousedown', this.hide, this);
37122 this.on('complete', this.updateNode, this);
37123 this.on('beforestartedit', this.fitToTree, this);
37124 this.on('startedit', this.bindScroll, this, {delay:10});
37125 this.on('specialkey', this.onSpecialKey, this);
37128 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
37130 * @cfg {String} alignment
37131 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
37137 * @cfg {Boolean} hideEl
37138 * True to hide the bound element while the editor is displayed (defaults to false)
37142 * @cfg {String} cls
37143 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
37145 cls: "x-small-editor x-tree-editor",
37147 * @cfg {Boolean} shim
37148 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
37154 * @cfg {Number} maxWidth
37155 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
37156 * the containing tree element's size, it will be automatically limited for you to the container width, taking
37157 * scroll and client offsets into account prior to each edit.
37164 fitToTree : function(ed, el){
37165 var td = this.tree.getTreeEl().dom, nd = el.dom;
37166 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
37167 td.scrollLeft = nd.offsetLeft;
37171 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
37172 this.setSize(w, '');
37174 return this.fireEvent('beforenodeedit', this, this.editNode);
37179 triggerEdit : function(node){
37180 this.completeEdit();
37181 this.editNode = node;
37182 this.startEdit(node.ui.textNode, node.text);
37186 bindScroll : function(){
37187 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
37191 beforeNodeClick : function(node, e){
37192 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
37193 this.lastClick = new Date();
37194 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
37196 this.triggerEdit(node);
37203 updateNode : function(ed, value){
37204 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
37205 this.editNode.setText(value);
37209 onHide : function(){
37210 Roo.tree.TreeEditor.superclass.onHide.call(this);
37212 this.editNode.ui.focus();
37217 onSpecialKey : function(field, e){
37218 var k = e.getKey();
37222 }else if(k == e.ENTER && !e.hasModifier()){
37224 this.completeEdit();
37227 });//<Script type="text/javascript">
37230 * Ext JS Library 1.1.1
37231 * Copyright(c) 2006-2007, Ext JS, LLC.
37233 * Originally Released Under LGPL - original licence link has changed is not relivant.
37236 * <script type="text/javascript">
37240 * Not documented??? - probably should be...
37243 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
37244 //focus: Roo.emptyFn, // prevent odd scrolling behavior
37246 renderElements : function(n, a, targetNode, bulkRender){
37247 //consel.log("renderElements?");
37248 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
37250 var t = n.getOwnerTree();
37251 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
37253 var cols = t.columns;
37254 var bw = t.borderWidth;
37256 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
37257 var cb = typeof a.checked == "boolean";
37258 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
37259 var colcls = 'x-t-' + tid + '-c0';
37261 '<li class="x-tree-node">',
37264 '<div class="x-tree-node-el ', a.cls,'">',
37266 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
37269 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
37270 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
37271 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
37272 (a.icon ? ' x-tree-node-inline-icon' : ''),
37273 (a.iconCls ? ' '+a.iconCls : ''),
37274 '" unselectable="on" />',
37275 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
37276 (a.checked ? 'checked="checked" />' : ' />')) : ''),
37278 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
37279 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
37280 '<span unselectable="on" qtip="' + tx + '">',
37284 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
37285 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
37287 for(var i = 1, len = cols.length; i < len; i++){
37289 colcls = 'x-t-' + tid + '-c' +i;
37290 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
37291 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
37292 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
37298 '<div class="x-clear"></div></div>',
37299 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
37302 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
37303 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
37304 n.nextSibling.ui.getEl(), buf.join(""));
37306 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
37308 var el = this.wrap.firstChild;
37310 this.elNode = el.firstChild;
37311 this.ranchor = el.childNodes[1];
37312 this.ctNode = this.wrap.childNodes[1];
37313 var cs = el.firstChild.childNodes;
37314 this.indentNode = cs[0];
37315 this.ecNode = cs[1];
37316 this.iconNode = cs[2];
37319 this.checkbox = cs[3];
37322 this.anchor = cs[index];
37324 this.textNode = cs[index].firstChild;
37326 //el.on("click", this.onClick, this);
37327 //el.on("dblclick", this.onDblClick, this);
37330 // console.log(this);
37332 initEvents : function(){
37333 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
37336 var a = this.ranchor;
37338 var el = Roo.get(a);
37340 if(Roo.isOpera){ // opera render bug ignores the CSS
37341 el.setStyle("text-decoration", "none");
37344 el.on("click", this.onClick, this);
37345 el.on("dblclick", this.onDblClick, this);
37346 el.on("contextmenu", this.onContextMenu, this);
37350 /*onSelectedChange : function(state){
37353 this.addClass("x-tree-selected");
37356 this.removeClass("x-tree-selected");
37359 addClass : function(cls){
37361 Roo.fly(this.elRow).addClass(cls);
37367 removeClass : function(cls){
37369 Roo.fly(this.elRow).removeClass(cls);
37375 });//<Script type="text/javascript">
37379 * Ext JS Library 1.1.1
37380 * Copyright(c) 2006-2007, Ext JS, LLC.
37382 * Originally Released Under LGPL - original licence link has changed is not relivant.
37385 * <script type="text/javascript">
37390 * @class Roo.tree.ColumnTree
37391 * @extends Roo.data.TreePanel
37392 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
37393 * @cfg {int} borderWidth compined right/left border allowance
37395 * @param {String/HTMLElement/Element} el The container element
37396 * @param {Object} config
37398 Roo.tree.ColumnTree = function(el, config)
37400 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
37404 * Fire this event on a container when it resizes
37405 * @param {int} w Width
37406 * @param {int} h Height
37410 this.on('resize', this.onResize, this);
37413 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
37417 borderWidth: Roo.isBorderBox ? 0 : 2,
37420 render : function(){
37421 // add the header.....
37423 Roo.tree.ColumnTree.superclass.render.apply(this);
37425 this.el.addClass('x-column-tree');
37427 this.headers = this.el.createChild(
37428 {cls:'x-tree-headers'},this.innerCt.dom);
37430 var cols = this.columns, c;
37431 var totalWidth = 0;
37433 var len = cols.length;
37434 for(var i = 0; i < len; i++){
37436 totalWidth += c.width;
37437 this.headEls.push(this.headers.createChild({
37438 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
37440 cls:'x-tree-hd-text',
37443 style:'width:'+(c.width-this.borderWidth)+'px;'
37446 this.headers.createChild({cls:'x-clear'});
37447 // prevent floats from wrapping when clipped
37448 this.headers.setWidth(totalWidth);
37449 //this.innerCt.setWidth(totalWidth);
37450 this.innerCt.setStyle({ overflow: 'auto' });
37451 this.onResize(this.width, this.height);
37455 onResize : function(w,h)
37460 this.innerCt.setWidth(this.width);
37461 this.innerCt.setHeight(this.height-20);
37464 var cols = this.columns, c;
37465 var totalWidth = 0;
37467 var len = cols.length;
37468 for(var i = 0; i < len; i++){
37470 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
37471 // it's the expander..
37472 expEl = this.headEls[i];
37475 totalWidth += c.width;
37479 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
37481 this.headers.setWidth(w-20);
37490 * Ext JS Library 1.1.1
37491 * Copyright(c) 2006-2007, Ext JS, LLC.
37493 * Originally Released Under LGPL - original licence link has changed is not relivant.
37496 * <script type="text/javascript">
37500 * @class Roo.menu.Menu
37501 * @extends Roo.util.Observable
37502 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
37503 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
37505 * Creates a new Menu
37506 * @param {Object} config Configuration options
37508 Roo.menu.Menu = function(config){
37510 Roo.menu.Menu.superclass.constructor.call(this, config);
37512 this.id = this.id || Roo.id();
37515 * @event beforeshow
37516 * Fires before this menu is displayed
37517 * @param {Roo.menu.Menu} this
37521 * @event beforehide
37522 * Fires before this menu is hidden
37523 * @param {Roo.menu.Menu} this
37528 * Fires after this menu is displayed
37529 * @param {Roo.menu.Menu} this
37534 * Fires after this menu is hidden
37535 * @param {Roo.menu.Menu} this
37540 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
37541 * @param {Roo.menu.Menu} this
37542 * @param {Roo.menu.Item} menuItem The menu item that was clicked
37543 * @param {Roo.EventObject} e
37548 * Fires when the mouse is hovering over this menu
37549 * @param {Roo.menu.Menu} this
37550 * @param {Roo.EventObject} e
37551 * @param {Roo.menu.Item} menuItem The menu item that was clicked
37556 * Fires when the mouse exits this menu
37557 * @param {Roo.menu.Menu} this
37558 * @param {Roo.EventObject} e
37559 * @param {Roo.menu.Item} menuItem The menu item that was clicked
37564 * Fires when a menu item contained in this menu is clicked
37565 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
37566 * @param {Roo.EventObject} e
37570 if (this.registerMenu) {
37571 Roo.menu.MenuMgr.register(this);
37574 var mis = this.items;
37575 this.items = new Roo.util.MixedCollection();
37577 this.add.apply(this, mis);
37581 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
37583 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
37587 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
37588 * for bottom-right shadow (defaults to "sides")
37592 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
37593 * this menu (defaults to "tl-tr?")
37595 subMenuAlign : "tl-tr?",
37597 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
37598 * relative to its element of origin (defaults to "tl-bl?")
37600 defaultAlign : "tl-bl?",
37602 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
37604 allowOtherMenus : false,
37606 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
37608 registerMenu : true,
37613 render : function(){
37617 var el = this.el = new Roo.Layer({
37619 shadow:this.shadow,
37621 parentEl: this.parentEl || document.body,
37625 this.keyNav = new Roo.menu.MenuNav(this);
37628 el.addClass("x-menu-plain");
37631 el.addClass(this.cls);
37633 // generic focus element
37634 this.focusEl = el.createChild({
37635 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
37637 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
37638 //disabling touch- as it's causing issues ..
37639 //ul.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
37640 ul.on('click' , this.onClick, this);
37643 ul.on("mouseover", this.onMouseOver, this);
37644 ul.on("mouseout", this.onMouseOut, this);
37645 this.items.each(function(item){
37650 var li = document.createElement("li");
37651 li.className = "x-menu-list-item";
37652 ul.dom.appendChild(li);
37653 item.render(li, this);
37660 autoWidth : function(){
37661 var el = this.el, ul = this.ul;
37665 var w = this.width;
37668 }else if(Roo.isIE){
37669 el.setWidth(this.minWidth);
37670 var t = el.dom.offsetWidth; // force recalc
37671 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
37676 delayAutoWidth : function(){
37679 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
37681 this.awTask.delay(20);
37686 findTargetItem : function(e){
37687 var t = e.getTarget(".x-menu-list-item", this.ul, true);
37688 if(t && t.menuItemId){
37689 return this.items.get(t.menuItemId);
37694 onClick : function(e){
37695 Roo.log("menu.onClick");
37696 var t = this.findTargetItem(e);
37701 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
37702 if(t == this.activeItem && t.shouldDeactivate(e)){
37703 this.activeItem.deactivate();
37704 delete this.activeItem;
37708 this.setActiveItem(t, true);
37716 this.fireEvent("click", this, t, e);
37720 setActiveItem : function(item, autoExpand){
37721 if(item != this.activeItem){
37722 if(this.activeItem){
37723 this.activeItem.deactivate();
37725 this.activeItem = item;
37726 item.activate(autoExpand);
37727 }else if(autoExpand){
37733 tryActivate : function(start, step){
37734 var items = this.items;
37735 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
37736 var item = items.get(i);
37737 if(!item.disabled && item.canActivate){
37738 this.setActiveItem(item, false);
37746 onMouseOver : function(e){
37748 if(t = this.findTargetItem(e)){
37749 if(t.canActivate && !t.disabled){
37750 this.setActiveItem(t, true);
37753 this.fireEvent("mouseover", this, e, t);
37757 onMouseOut : function(e){
37759 if(t = this.findTargetItem(e)){
37760 if(t == this.activeItem && t.shouldDeactivate(e)){
37761 this.activeItem.deactivate();
37762 delete this.activeItem;
37765 this.fireEvent("mouseout", this, e, t);
37769 * Read-only. Returns true if the menu is currently displayed, else false.
37772 isVisible : function(){
37773 return this.el && !this.hidden;
37777 * Displays this menu relative to another element
37778 * @param {String/HTMLElement/Roo.Element} element The element to align to
37779 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
37780 * the element (defaults to this.defaultAlign)
37781 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
37783 show : function(el, pos, parentMenu){
37784 this.parentMenu = parentMenu;
37788 this.fireEvent("beforeshow", this);
37789 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
37793 * Displays this menu at a specific xy position
37794 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
37795 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
37797 showAt : function(xy, parentMenu, /* private: */_e){
37798 this.parentMenu = parentMenu;
37803 this.fireEvent("beforeshow", this);
37804 xy = this.el.adjustForConstraints(xy);
37808 this.hidden = false;
37810 this.fireEvent("show", this);
37813 focus : function(){
37815 this.doFocus.defer(50, this);
37819 doFocus : function(){
37821 this.focusEl.focus();
37826 * Hides this menu and optionally all parent menus
37827 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
37829 hide : function(deep){
37830 if(this.el && this.isVisible()){
37831 this.fireEvent("beforehide", this);
37832 if(this.activeItem){
37833 this.activeItem.deactivate();
37834 this.activeItem = null;
37837 this.hidden = true;
37838 this.fireEvent("hide", this);
37840 if(deep === true && this.parentMenu){
37841 this.parentMenu.hide(true);
37846 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
37847 * Any of the following are valid:
37849 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
37850 * <li>An HTMLElement object which will be converted to a menu item</li>
37851 * <li>A menu item config object that will be created as a new menu item</li>
37852 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
37853 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
37858 var menu = new Roo.menu.Menu();
37860 // Create a menu item to add by reference
37861 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
37863 // Add a bunch of items at once using different methods.
37864 // Only the last item added will be returned.
37865 var item = menu.add(
37866 menuItem, // add existing item by ref
37867 'Dynamic Item', // new TextItem
37868 '-', // new separator
37869 { text: 'Config Item' } // new item by config
37872 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
37873 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
37876 var a = arguments, l = a.length, item;
37877 for(var i = 0; i < l; i++){
37879 if ((typeof(el) == "object") && el.xtype && el.xns) {
37880 el = Roo.factory(el, Roo.menu);
37883 if(el.render){ // some kind of Item
37884 item = this.addItem(el);
37885 }else if(typeof el == "string"){ // string
37886 if(el == "separator" || el == "-"){
37887 item = this.addSeparator();
37889 item = this.addText(el);
37891 }else if(el.tagName || el.el){ // element
37892 item = this.addElement(el);
37893 }else if(typeof el == "object"){ // must be menu item config?
37894 item = this.addMenuItem(el);
37901 * Returns this menu's underlying {@link Roo.Element} object
37902 * @return {Roo.Element} The element
37904 getEl : function(){
37912 * Adds a separator bar to the menu
37913 * @return {Roo.menu.Item} The menu item that was added
37915 addSeparator : function(){
37916 return this.addItem(new Roo.menu.Separator());
37920 * Adds an {@link Roo.Element} object to the menu
37921 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
37922 * @return {Roo.menu.Item} The menu item that was added
37924 addElement : function(el){
37925 return this.addItem(new Roo.menu.BaseItem(el));
37929 * Adds an existing object based on {@link Roo.menu.Item} to the menu
37930 * @param {Roo.menu.Item} item The menu item to add
37931 * @return {Roo.menu.Item} The menu item that was added
37933 addItem : function(item){
37934 this.items.add(item);
37936 var li = document.createElement("li");
37937 li.className = "x-menu-list-item";
37938 this.ul.dom.appendChild(li);
37939 item.render(li, this);
37940 this.delayAutoWidth();
37946 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
37947 * @param {Object} config A MenuItem config object
37948 * @return {Roo.menu.Item} The menu item that was added
37950 addMenuItem : function(config){
37951 if(!(config instanceof Roo.menu.Item)){
37952 if(typeof config.checked == "boolean"){ // must be check menu item config?
37953 config = new Roo.menu.CheckItem(config);
37955 config = new Roo.menu.Item(config);
37958 return this.addItem(config);
37962 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
37963 * @param {String} text The text to display in the menu item
37964 * @return {Roo.menu.Item} The menu item that was added
37966 addText : function(text){
37967 return this.addItem(new Roo.menu.TextItem({ text : text }));
37971 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
37972 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
37973 * @param {Roo.menu.Item} item The menu item to add
37974 * @return {Roo.menu.Item} The menu item that was added
37976 insert : function(index, item){
37977 this.items.insert(index, item);
37979 var li = document.createElement("li");
37980 li.className = "x-menu-list-item";
37981 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
37982 item.render(li, this);
37983 this.delayAutoWidth();
37989 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
37990 * @param {Roo.menu.Item} item The menu item to remove
37992 remove : function(item){
37993 this.items.removeKey(item.id);
37998 * Removes and destroys all items in the menu
38000 removeAll : function(){
38002 while(f = this.items.first()){
38008 // MenuNav is a private utility class used internally by the Menu
38009 Roo.menu.MenuNav = function(menu){
38010 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
38011 this.scope = this.menu = menu;
38014 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
38015 doRelay : function(e, h){
38016 var k = e.getKey();
38017 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
38018 this.menu.tryActivate(0, 1);
38021 return h.call(this.scope || this, e, this.menu);
38024 up : function(e, m){
38025 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
38026 m.tryActivate(m.items.length-1, -1);
38030 down : function(e, m){
38031 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
38032 m.tryActivate(0, 1);
38036 right : function(e, m){
38038 m.activeItem.expandMenu(true);
38042 left : function(e, m){
38044 if(m.parentMenu && m.parentMenu.activeItem){
38045 m.parentMenu.activeItem.activate();
38049 enter : function(e, m){
38051 e.stopPropagation();
38052 m.activeItem.onClick(e);
38053 m.fireEvent("click", this, m.activeItem);
38059 * Ext JS Library 1.1.1
38060 * Copyright(c) 2006-2007, Ext JS, LLC.
38062 * Originally Released Under LGPL - original licence link has changed is not relivant.
38065 * <script type="text/javascript">
38069 * @class Roo.menu.MenuMgr
38070 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
38073 Roo.menu.MenuMgr = function(){
38074 var menus, active, groups = {}, attached = false, lastShow = new Date();
38076 // private - called when first menu is created
38079 active = new Roo.util.MixedCollection();
38080 Roo.get(document).addKeyListener(27, function(){
38081 if(active.length > 0){
38088 function hideAll(){
38089 if(active && active.length > 0){
38090 var c = active.clone();
38091 c.each(function(m){
38098 function onHide(m){
38100 if(active.length < 1){
38101 Roo.get(document).un("mousedown", onMouseDown);
38107 function onShow(m){
38108 var last = active.last();
38109 lastShow = new Date();
38112 Roo.get(document).on("mousedown", onMouseDown);
38116 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
38117 m.parentMenu.activeChild = m;
38118 }else if(last && last.isVisible()){
38119 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
38124 function onBeforeHide(m){
38126 m.activeChild.hide();
38128 if(m.autoHideTimer){
38129 clearTimeout(m.autoHideTimer);
38130 delete m.autoHideTimer;
38135 function onBeforeShow(m){
38136 var pm = m.parentMenu;
38137 if(!pm && !m.allowOtherMenus){
38139 }else if(pm && pm.activeChild && active != m){
38140 pm.activeChild.hide();
38145 function onMouseDown(e){
38146 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
38152 function onBeforeCheck(mi, state){
38154 var g = groups[mi.group];
38155 for(var i = 0, l = g.length; i < l; i++){
38157 g[i].setChecked(false);
38166 * Hides all menus that are currently visible
38168 hideAll : function(){
38173 register : function(menu){
38177 menus[menu.id] = menu;
38178 menu.on("beforehide", onBeforeHide);
38179 menu.on("hide", onHide);
38180 menu.on("beforeshow", onBeforeShow);
38181 menu.on("show", onShow);
38182 var g = menu.group;
38183 if(g && menu.events["checkchange"]){
38187 groups[g].push(menu);
38188 menu.on("checkchange", onCheck);
38193 * Returns a {@link Roo.menu.Menu} object
38194 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
38195 * be used to generate and return a new Menu instance.
38197 get : function(menu){
38198 if(typeof menu == "string"){ // menu id
38199 return menus[menu];
38200 }else if(menu.events){ // menu instance
38202 }else if(typeof menu.length == 'number'){ // array of menu items?
38203 return new Roo.menu.Menu({items:menu});
38204 }else{ // otherwise, must be a config
38205 return new Roo.menu.Menu(menu);
38210 unregister : function(menu){
38211 delete menus[menu.id];
38212 menu.un("beforehide", onBeforeHide);
38213 menu.un("hide", onHide);
38214 menu.un("beforeshow", onBeforeShow);
38215 menu.un("show", onShow);
38216 var g = menu.group;
38217 if(g && menu.events["checkchange"]){
38218 groups[g].remove(menu);
38219 menu.un("checkchange", onCheck);
38224 registerCheckable : function(menuItem){
38225 var g = menuItem.group;
38230 groups[g].push(menuItem);
38231 menuItem.on("beforecheckchange", onBeforeCheck);
38236 unregisterCheckable : function(menuItem){
38237 var g = menuItem.group;
38239 groups[g].remove(menuItem);
38240 menuItem.un("beforecheckchange", onBeforeCheck);
38246 * Ext JS Library 1.1.1
38247 * Copyright(c) 2006-2007, Ext JS, LLC.
38249 * Originally Released Under LGPL - original licence link has changed is not relivant.
38252 * <script type="text/javascript">
38257 * @class Roo.menu.BaseItem
38258 * @extends Roo.Component
38259 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
38260 * management and base configuration options shared by all menu components.
38262 * Creates a new BaseItem
38263 * @param {Object} config Configuration options
38265 Roo.menu.BaseItem = function(config){
38266 Roo.menu.BaseItem.superclass.constructor.call(this, config);
38271 * Fires when this item is clicked
38272 * @param {Roo.menu.BaseItem} this
38273 * @param {Roo.EventObject} e
38278 * Fires when this item is activated
38279 * @param {Roo.menu.BaseItem} this
38283 * @event deactivate
38284 * Fires when this item is deactivated
38285 * @param {Roo.menu.BaseItem} this
38291 this.on("click", this.handler, this.scope, true);
38295 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
38297 * @cfg {Function} handler
38298 * A function that will handle the click event of this menu item (defaults to undefined)
38301 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
38303 canActivate : false,
38306 * @cfg {Boolean} hidden True to prevent creation of this menu item (defaults to false)
38311 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
38313 activeClass : "x-menu-item-active",
38315 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
38317 hideOnClick : true,
38319 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
38324 ctype: "Roo.menu.BaseItem",
38327 actionMode : "container",
38330 render : function(container, parentMenu){
38331 this.parentMenu = parentMenu;
38332 Roo.menu.BaseItem.superclass.render.call(this, container);
38333 this.container.menuItemId = this.id;
38337 onRender : function(container, position){
38338 this.el = Roo.get(this.el);
38339 container.dom.appendChild(this.el.dom);
38343 onClick : function(e){
38344 if(!this.disabled && this.fireEvent("click", this, e) !== false
38345 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
38346 this.handleClick(e);
38353 activate : function(){
38357 var li = this.container;
38358 li.addClass(this.activeClass);
38359 this.region = li.getRegion().adjust(2, 2, -2, -2);
38360 this.fireEvent("activate", this);
38365 deactivate : function(){
38366 this.container.removeClass(this.activeClass);
38367 this.fireEvent("deactivate", this);
38371 shouldDeactivate : function(e){
38372 return !this.region || !this.region.contains(e.getPoint());
38376 handleClick : function(e){
38377 if(this.hideOnClick){
38378 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
38383 expandMenu : function(autoActivate){
38388 hideMenu : function(){
38393 * Ext JS Library 1.1.1
38394 * Copyright(c) 2006-2007, Ext JS, LLC.
38396 * Originally Released Under LGPL - original licence link has changed is not relivant.
38399 * <script type="text/javascript">
38403 * @class Roo.menu.Adapter
38404 * @extends Roo.menu.BaseItem
38405 * 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.
38406 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
38408 * Creates a new Adapter
38409 * @param {Object} config Configuration options
38411 Roo.menu.Adapter = function(component, config){
38412 Roo.menu.Adapter.superclass.constructor.call(this, config);
38413 this.component = component;
38415 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
38417 canActivate : true,
38420 onRender : function(container, position){
38421 this.component.render(container);
38422 this.el = this.component.getEl();
38426 activate : function(){
38430 this.component.focus();
38431 this.fireEvent("activate", this);
38436 deactivate : function(){
38437 this.fireEvent("deactivate", this);
38441 disable : function(){
38442 this.component.disable();
38443 Roo.menu.Adapter.superclass.disable.call(this);
38447 enable : function(){
38448 this.component.enable();
38449 Roo.menu.Adapter.superclass.enable.call(this);
38453 * Ext JS Library 1.1.1
38454 * Copyright(c) 2006-2007, Ext JS, LLC.
38456 * Originally Released Under LGPL - original licence link has changed is not relivant.
38459 * <script type="text/javascript">
38463 * @class Roo.menu.TextItem
38464 * @extends Roo.menu.BaseItem
38465 * Adds a static text string to a menu, usually used as either a heading or group separator.
38466 * Note: old style constructor with text is still supported.
38469 * Creates a new TextItem
38470 * @param {Object} cfg Configuration
38472 Roo.menu.TextItem = function(cfg){
38473 if (typeof(cfg) == 'string') {
38476 Roo.apply(this,cfg);
38479 Roo.menu.TextItem.superclass.constructor.call(this);
38482 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
38484 * @cfg {String} text Text to show on item.
38489 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
38491 hideOnClick : false,
38493 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
38495 itemCls : "x-menu-text",
38498 onRender : function(){
38499 var s = document.createElement("span");
38500 s.className = this.itemCls;
38501 s.innerHTML = this.text;
38503 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
38507 * Ext JS Library 1.1.1
38508 * Copyright(c) 2006-2007, Ext JS, LLC.
38510 * Originally Released Under LGPL - original licence link has changed is not relivant.
38513 * <script type="text/javascript">
38517 * @class Roo.menu.Separator
38518 * @extends Roo.menu.BaseItem
38519 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
38520 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
38522 * @param {Object} config Configuration options
38524 Roo.menu.Separator = function(config){
38525 Roo.menu.Separator.superclass.constructor.call(this, config);
38528 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
38530 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
38532 itemCls : "x-menu-sep",
38534 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
38536 hideOnClick : false,
38539 onRender : function(li){
38540 var s = document.createElement("span");
38541 s.className = this.itemCls;
38542 s.innerHTML = " ";
38544 li.addClass("x-menu-sep-li");
38545 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
38549 * Ext JS Library 1.1.1
38550 * Copyright(c) 2006-2007, Ext JS, LLC.
38552 * Originally Released Under LGPL - original licence link has changed is not relivant.
38555 * <script type="text/javascript">
38558 * @class Roo.menu.Item
38559 * @extends Roo.menu.BaseItem
38560 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
38561 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
38562 * activation and click handling.
38564 * Creates a new Item
38565 * @param {Object} config Configuration options
38567 Roo.menu.Item = function(config){
38568 Roo.menu.Item.superclass.constructor.call(this, config);
38570 this.menu = Roo.menu.MenuMgr.get(this.menu);
38573 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
38576 * @cfg {String} text
38577 * The text to show on the menu item.
38581 * @cfg {String} HTML to render in menu
38582 * The text to show on the menu item (HTML version).
38586 * @cfg {String} icon
38587 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
38591 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
38593 itemCls : "x-menu-item",
38595 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
38597 canActivate : true,
38599 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
38602 // doc'd in BaseItem
38606 ctype: "Roo.menu.Item",
38609 onRender : function(container, position){
38610 var el = document.createElement("a");
38611 el.hideFocus = true;
38612 el.unselectable = "on";
38613 el.href = this.href || "#";
38614 if(this.hrefTarget){
38615 el.target = this.hrefTarget;
38617 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
38619 var html = this.html.length ? this.html : String.format('{0}',this.text);
38621 el.innerHTML = String.format(
38622 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
38623 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
38625 Roo.menu.Item.superclass.onRender.call(this, container, position);
38629 * Sets the text to display in this menu item
38630 * @param {String} text The text to display
38631 * @param {Boolean} isHTML true to indicate text is pure html.
38633 setText : function(text, isHTML){
38641 var html = this.html.length ? this.html : String.format('{0}',this.text);
38643 this.el.update(String.format(
38644 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
38645 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
38646 this.parentMenu.autoWidth();
38651 handleClick : function(e){
38652 if(!this.href){ // if no link defined, stop the event automatically
38655 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
38659 activate : function(autoExpand){
38660 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
38670 shouldDeactivate : function(e){
38671 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
38672 if(this.menu && this.menu.isVisible()){
38673 return !this.menu.getEl().getRegion().contains(e.getPoint());
38681 deactivate : function(){
38682 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
38687 expandMenu : function(autoActivate){
38688 if(!this.disabled && this.menu){
38689 clearTimeout(this.hideTimer);
38690 delete this.hideTimer;
38691 if(!this.menu.isVisible() && !this.showTimer){
38692 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
38693 }else if (this.menu.isVisible() && autoActivate){
38694 this.menu.tryActivate(0, 1);
38700 deferExpand : function(autoActivate){
38701 delete this.showTimer;
38702 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
38704 this.menu.tryActivate(0, 1);
38709 hideMenu : function(){
38710 clearTimeout(this.showTimer);
38711 delete this.showTimer;
38712 if(!this.hideTimer && this.menu && this.menu.isVisible()){
38713 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
38718 deferHide : function(){
38719 delete this.hideTimer;
38724 * Ext JS Library 1.1.1
38725 * Copyright(c) 2006-2007, Ext JS, LLC.
38727 * Originally Released Under LGPL - original licence link has changed is not relivant.
38730 * <script type="text/javascript">
38734 * @class Roo.menu.CheckItem
38735 * @extends Roo.menu.Item
38736 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
38738 * Creates a new CheckItem
38739 * @param {Object} config Configuration options
38741 Roo.menu.CheckItem = function(config){
38742 Roo.menu.CheckItem.superclass.constructor.call(this, config);
38745 * @event beforecheckchange
38746 * Fires before the checked value is set, providing an opportunity to cancel if needed
38747 * @param {Roo.menu.CheckItem} this
38748 * @param {Boolean} checked The new checked value that will be set
38750 "beforecheckchange" : true,
38752 * @event checkchange
38753 * Fires after the checked value has been set
38754 * @param {Roo.menu.CheckItem} this
38755 * @param {Boolean} checked The checked value that was set
38757 "checkchange" : true
38759 if(this.checkHandler){
38760 this.on('checkchange', this.checkHandler, this.scope);
38763 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
38765 * @cfg {String} group
38766 * All check items with the same group name will automatically be grouped into a single-select
38767 * radio button group (defaults to '')
38770 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
38772 itemCls : "x-menu-item x-menu-check-item",
38774 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
38776 groupClass : "x-menu-group-item",
38779 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
38780 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
38781 * initialized with checked = true will be rendered as checked.
38786 ctype: "Roo.menu.CheckItem",
38789 onRender : function(c){
38790 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
38792 this.el.addClass(this.groupClass);
38794 Roo.menu.MenuMgr.registerCheckable(this);
38796 this.checked = false;
38797 this.setChecked(true, true);
38802 destroy : function(){
38804 Roo.menu.MenuMgr.unregisterCheckable(this);
38806 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
38810 * Set the checked state of this item
38811 * @param {Boolean} checked The new checked value
38812 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
38814 setChecked : function(state, suppressEvent){
38815 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
38816 if(this.container){
38817 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
38819 this.checked = state;
38820 if(suppressEvent !== true){
38821 this.fireEvent("checkchange", this, state);
38827 handleClick : function(e){
38828 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
38829 this.setChecked(!this.checked);
38831 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
38835 * Ext JS Library 1.1.1
38836 * Copyright(c) 2006-2007, Ext JS, LLC.
38838 * Originally Released Under LGPL - original licence link has changed is not relivant.
38841 * <script type="text/javascript">
38845 * @class Roo.menu.DateItem
38846 * @extends Roo.menu.Adapter
38847 * A menu item that wraps the {@link Roo.DatPicker} component.
38849 * Creates a new DateItem
38850 * @param {Object} config Configuration options
38852 Roo.menu.DateItem = function(config){
38853 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
38854 /** The Roo.DatePicker object @type Roo.DatePicker */
38855 this.picker = this.component;
38856 this.addEvents({select: true});
38858 this.picker.on("render", function(picker){
38859 picker.getEl().swallowEvent("click");
38860 picker.container.addClass("x-menu-date-item");
38863 this.picker.on("select", this.onSelect, this);
38866 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
38868 onSelect : function(picker, date){
38869 this.fireEvent("select", this, date, picker);
38870 Roo.menu.DateItem.superclass.handleClick.call(this);
38874 * Ext JS Library 1.1.1
38875 * Copyright(c) 2006-2007, Ext JS, LLC.
38877 * Originally Released Under LGPL - original licence link has changed is not relivant.
38880 * <script type="text/javascript">
38884 * @class Roo.menu.ColorItem
38885 * @extends Roo.menu.Adapter
38886 * A menu item that wraps the {@link Roo.ColorPalette} component.
38888 * Creates a new ColorItem
38889 * @param {Object} config Configuration options
38891 Roo.menu.ColorItem = function(config){
38892 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
38893 /** The Roo.ColorPalette object @type Roo.ColorPalette */
38894 this.palette = this.component;
38895 this.relayEvents(this.palette, ["select"]);
38896 if(this.selectHandler){
38897 this.on('select', this.selectHandler, this.scope);
38900 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
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">
38913 * @class Roo.menu.DateMenu
38914 * @extends Roo.menu.Menu
38915 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
38917 * Creates a new DateMenu
38918 * @param {Object} config Configuration options
38920 Roo.menu.DateMenu = function(config){
38921 Roo.menu.DateMenu.superclass.constructor.call(this, config);
38923 var di = new Roo.menu.DateItem(config);
38926 * The {@link Roo.DatePicker} instance for this DateMenu
38929 this.picker = di.picker;
38932 * @param {DatePicker} picker
38933 * @param {Date} date
38935 this.relayEvents(di, ["select"]);
38936 this.on('beforeshow', function(){
38938 this.picker.hideMonthPicker(false);
38942 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
38946 * Ext JS Library 1.1.1
38947 * Copyright(c) 2006-2007, Ext JS, LLC.
38949 * Originally Released Under LGPL - original licence link has changed is not relivant.
38952 * <script type="text/javascript">
38957 * @class Roo.menu.ColorMenu
38958 * @extends Roo.menu.Menu
38959 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
38961 * Creates a new ColorMenu
38962 * @param {Object} config Configuration options
38964 Roo.menu.ColorMenu = function(config){
38965 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
38967 var ci = new Roo.menu.ColorItem(config);
38970 * The {@link Roo.ColorPalette} instance for this ColorMenu
38971 * @type ColorPalette
38973 this.palette = ci.palette;
38976 * @param {ColorPalette} palette
38977 * @param {String} color
38979 this.relayEvents(ci, ["select"]);
38981 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
38983 * Ext JS Library 1.1.1
38984 * Copyright(c) 2006-2007, Ext JS, LLC.
38986 * Originally Released Under LGPL - original licence link has changed is not relivant.
38989 * <script type="text/javascript">
38993 * @class Roo.form.TextItem
38994 * @extends Roo.BoxComponent
38995 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
38997 * Creates a new TextItem
38998 * @param {Object} config Configuration options
39000 Roo.form.TextItem = function(config){
39001 Roo.form.TextItem.superclass.constructor.call(this, config);
39004 Roo.extend(Roo.form.TextItem, Roo.BoxComponent, {
39007 * @cfg {String} tag the tag for this item (default div)
39011 * @cfg {String} html the content for this item
39015 getAutoCreate : function()
39028 onRender : function(ct, position)
39030 Roo.form.TextItem.superclass.onRender.call(this, ct, position);
39033 var cfg = this.getAutoCreate();
39035 cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
39037 if (!cfg.name.length) {
39040 this.el = ct.createChild(cfg, position);
39045 * @param {String} html update the Contents of the element.
39047 setHTML : function(html)
39049 this.fieldEl.dom.innerHTML = html;
39054 * Ext JS Library 1.1.1
39055 * Copyright(c) 2006-2007, Ext JS, LLC.
39057 * Originally Released Under LGPL - original licence link has changed is not relivant.
39060 * <script type="text/javascript">
39064 * @class Roo.form.Field
39065 * @extends Roo.BoxComponent
39066 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
39068 * Creates a new Field
39069 * @param {Object} config Configuration options
39071 Roo.form.Field = function(config){
39072 Roo.form.Field.superclass.constructor.call(this, config);
39075 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
39077 * @cfg {String} fieldLabel Label to use when rendering a form.
39080 * @cfg {String} qtip Mouse over tip
39084 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
39086 invalidClass : "x-form-invalid",
39088 * @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")
39090 invalidText : "The value in this field is invalid",
39092 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
39094 focusClass : "x-form-focus",
39096 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
39097 automatic validation (defaults to "keyup").
39099 validationEvent : "keyup",
39101 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
39103 validateOnBlur : true,
39105 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
39107 validationDelay : 250,
39109 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
39110 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
39112 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "new-password"},
39114 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
39116 fieldClass : "x-form-field",
39118 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
39121 ----------- ----------------------------------------------------------------------
39122 qtip Display a quick tip when the user hovers over the field
39123 title Display a default browser title attribute popup
39124 under Add a block div beneath the field containing the error text
39125 side Add an error icon to the right of the field with a popup on hover
39126 [element id] Add the error text directly to the innerHTML of the specified element
39129 msgTarget : 'qtip',
39131 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
39136 * @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.
39141 * @cfg {Boolean} disabled True to disable the field (defaults to false).
39146 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
39148 inputType : undefined,
39151 * @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).
39153 tabIndex : undefined,
39156 isFormField : true,
39161 * @property {Roo.Element} fieldEl
39162 * Element Containing the rendered Field (with label etc.)
39165 * @cfg {Mixed} value A value to initialize this field with.
39170 * @cfg {String} name The field's HTML name attribute.
39173 * @cfg {String} cls A CSS class to apply to the field's underlying element.
39176 loadedValue : false,
39180 initComponent : function(){
39181 Roo.form.Field.superclass.initComponent.call(this);
39185 * Fires when this field receives input focus.
39186 * @param {Roo.form.Field} this
39191 * Fires when this field loses input focus.
39192 * @param {Roo.form.Field} this
39196 * @event specialkey
39197 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
39198 * {@link Roo.EventObject#getKey} to determine which key was pressed.
39199 * @param {Roo.form.Field} this
39200 * @param {Roo.EventObject} e The event object
39205 * Fires just before the field blurs if the field value has changed.
39206 * @param {Roo.form.Field} this
39207 * @param {Mixed} newValue The new value
39208 * @param {Mixed} oldValue The original value
39213 * Fires after the field has been marked as invalid.
39214 * @param {Roo.form.Field} this
39215 * @param {String} msg The validation message
39220 * Fires after the field has been validated with no errors.
39221 * @param {Roo.form.Field} this
39226 * Fires after the key up
39227 * @param {Roo.form.Field} this
39228 * @param {Roo.EventObject} e The event Object
39235 * Returns the name attribute of the field if available
39236 * @return {String} name The field name
39238 getName: function(){
39239 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
39243 onRender : function(ct, position){
39244 Roo.form.Field.superclass.onRender.call(this, ct, position);
39246 var cfg = this.getAutoCreate();
39248 cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
39250 if (!cfg.name.length) {
39253 if(this.inputType){
39254 cfg.type = this.inputType;
39256 this.el = ct.createChild(cfg, position);
39258 var type = this.el.dom.type;
39260 if(type == 'password'){
39263 this.el.addClass('x-form-'+type);
39266 this.el.dom.readOnly = true;
39268 if(this.tabIndex !== undefined){
39269 this.el.dom.setAttribute('tabIndex', this.tabIndex);
39272 this.el.addClass([this.fieldClass, this.cls]);
39277 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
39278 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
39279 * @return {Roo.form.Field} this
39281 applyTo : function(target){
39282 this.allowDomMove = false;
39283 this.el = Roo.get(target);
39284 this.render(this.el.dom.parentNode);
39289 initValue : function(){
39290 if(this.value !== undefined){
39291 this.setValue(this.value);
39292 }else if(this.el.dom.value.length > 0){
39293 this.setValue(this.el.dom.value);
39298 * Returns true if this field has been changed since it was originally loaded and is not disabled.
39299 * DEPRICATED - it never worked well - use hasChanged/resetHasChanged.
39301 isDirty : function() {
39302 if(this.disabled) {
39305 return String(this.getValue()) !== String(this.originalValue);
39309 * stores the current value in loadedValue
39311 resetHasChanged : function()
39313 this.loadedValue = String(this.getValue());
39316 * checks the current value against the 'loaded' value.
39317 * Note - will return false if 'resetHasChanged' has not been called first.
39319 hasChanged : function()
39321 if(this.disabled || this.readOnly) {
39324 return this.loadedValue !== false && String(this.getValue()) !== this.loadedValue;
39330 afterRender : function(){
39331 Roo.form.Field.superclass.afterRender.call(this);
39336 fireKey : function(e){
39337 //Roo.log('field ' + e.getKey());
39338 if(e.isNavKeyPress()){
39339 this.fireEvent("specialkey", this, e);
39344 * Resets the current field value to the originally loaded value and clears any validation messages
39346 reset : function(){
39347 this.setValue(this.resetValue);
39348 this.originalValue = this.getValue();
39349 this.clearInvalid();
39353 initEvents : function(){
39354 // safari killled keypress - so keydown is now used..
39355 this.el.on("keydown" , this.fireKey, this);
39356 this.el.on("focus", this.onFocus, this);
39357 this.el.on("blur", this.onBlur, this);
39358 this.el.relayEvent('keyup', this);
39360 // reference to original value for reset
39361 this.originalValue = this.getValue();
39362 this.resetValue = this.getValue();
39366 onFocus : function(){
39367 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
39368 this.el.addClass(this.focusClass);
39370 if(!this.hasFocus){
39371 this.hasFocus = true;
39372 this.startValue = this.getValue();
39373 this.fireEvent("focus", this);
39377 beforeBlur : Roo.emptyFn,
39380 onBlur : function(){
39382 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
39383 this.el.removeClass(this.focusClass);
39385 this.hasFocus = false;
39386 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
39389 var v = this.getValue();
39390 if(String(v) !== String(this.startValue)){
39391 this.fireEvent('change', this, v, this.startValue);
39393 this.fireEvent("blur", this);
39397 * Returns whether or not the field value is currently valid
39398 * @param {Boolean} preventMark True to disable marking the field invalid
39399 * @return {Boolean} True if the value is valid, else false
39401 isValid : function(preventMark){
39405 var restore = this.preventMark;
39406 this.preventMark = preventMark === true;
39407 var v = this.validateValue(this.processValue(this.getRawValue()));
39408 this.preventMark = restore;
39413 * Validates the field value
39414 * @return {Boolean} True if the value is valid, else false
39416 validate : function(){
39417 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
39418 this.clearInvalid();
39424 processValue : function(value){
39429 // Subclasses should provide the validation implementation by overriding this
39430 validateValue : function(value){
39435 * Mark this field as invalid
39436 * @param {String} msg The validation message
39438 markInvalid : function(msg){
39439 if(!this.rendered || this.preventMark){ // not rendered
39443 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
39445 obj.el.addClass(this.invalidClass);
39446 msg = msg || this.invalidText;
39447 switch(this.msgTarget){
39449 obj.el.dom.qtip = msg;
39450 obj.el.dom.qclass = 'x-form-invalid-tip';
39451 if(Roo.QuickTips){ // fix for floating editors interacting with DND
39452 Roo.QuickTips.enable();
39456 this.el.dom.title = msg;
39460 var elp = this.el.findParent('.x-form-element', 5, true);
39461 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
39462 this.errorEl.setWidth(elp.getWidth(true)-20);
39464 this.errorEl.update(msg);
39465 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
39468 if(!this.errorIcon){
39469 var elp = this.el.findParent('.x-form-element', 5, true);
39470 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
39472 this.alignErrorIcon();
39473 this.errorIcon.dom.qtip = msg;
39474 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
39475 this.errorIcon.show();
39476 this.on('resize', this.alignErrorIcon, this);
39479 var t = Roo.getDom(this.msgTarget);
39481 t.style.display = this.msgDisplay;
39484 this.fireEvent('invalid', this, msg);
39488 alignErrorIcon : function(){
39489 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
39493 * Clear any invalid styles/messages for this field
39495 clearInvalid : function(){
39496 if(!this.rendered || this.preventMark){ // not rendered
39499 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
39501 obj.el.removeClass(this.invalidClass);
39502 switch(this.msgTarget){
39504 obj.el.dom.qtip = '';
39507 this.el.dom.title = '';
39511 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
39515 if(this.errorIcon){
39516 this.errorIcon.dom.qtip = '';
39517 this.errorIcon.hide();
39518 this.un('resize', this.alignErrorIcon, this);
39522 var t = Roo.getDom(this.msgTarget);
39524 t.style.display = 'none';
39527 this.fireEvent('valid', this);
39531 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
39532 * @return {Mixed} value The field value
39534 getRawValue : function(){
39535 var v = this.el.getValue();
39541 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
39542 * @return {Mixed} value The field value
39544 getValue : function(){
39545 var v = this.el.getValue();
39551 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
39552 * @param {Mixed} value The value to set
39554 setRawValue : function(v){
39555 return this.el.dom.value = (v === null || v === undefined ? '' : v);
39559 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
39560 * @param {Mixed} value The value to set
39562 setValue : function(v){
39565 this.el.dom.value = (v === null || v === undefined ? '' : v);
39570 adjustSize : function(w, h){
39571 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
39572 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
39576 adjustWidth : function(tag, w){
39577 tag = tag.toLowerCase();
39578 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
39579 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
39580 if(tag == 'input'){
39583 if(tag == 'textarea'){
39586 }else if(Roo.isOpera){
39587 if(tag == 'input'){
39590 if(tag == 'textarea'){
39600 // anything other than normal should be considered experimental
39601 Roo.form.Field.msgFx = {
39603 show: function(msgEl, f){
39604 msgEl.setDisplayed('block');
39607 hide : function(msgEl, f){
39608 msgEl.setDisplayed(false).update('');
39613 show: function(msgEl, f){
39614 msgEl.slideIn('t', {stopFx:true});
39617 hide : function(msgEl, f){
39618 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
39623 show: function(msgEl, f){
39624 msgEl.fixDisplay();
39625 msgEl.alignTo(f.el, 'tl-tr');
39626 msgEl.slideIn('l', {stopFx:true});
39629 hide : function(msgEl, f){
39630 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
39635 * Ext JS Library 1.1.1
39636 * Copyright(c) 2006-2007, Ext JS, LLC.
39638 * Originally Released Under LGPL - original licence link has changed is not relivant.
39641 * <script type="text/javascript">
39646 * @class Roo.form.TextField
39647 * @extends Roo.form.Field
39648 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
39649 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
39651 * Creates a new TextField
39652 * @param {Object} config Configuration options
39654 Roo.form.TextField = function(config){
39655 Roo.form.TextField.superclass.constructor.call(this, config);
39659 * Fires when the autosize function is triggered. The field may or may not have actually changed size
39660 * according to the default logic, but this event provides a hook for the developer to apply additional
39661 * logic at runtime to resize the field if needed.
39662 * @param {Roo.form.Field} this This text field
39663 * @param {Number} width The new field width
39669 Roo.extend(Roo.form.TextField, Roo.form.Field, {
39671 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
39675 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
39679 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
39683 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
39687 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
39691 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
39693 disableKeyFilter : false,
39695 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
39699 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
39703 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
39705 maxLength : Number.MAX_VALUE,
39707 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
39709 minLengthText : "The minimum length for this field is {0}",
39711 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
39713 maxLengthText : "The maximum length for this field is {0}",
39715 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
39717 selectOnFocus : false,
39719 * @cfg {Boolean} allowLeadingSpace True to prevent the stripping of leading white space
39721 allowLeadingSpace : false,
39723 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
39725 blankText : "This field is required",
39727 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
39728 * If available, this function will be called only after the basic validators all return true, and will be passed the
39729 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
39733 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
39734 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
39735 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
39739 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
39743 * @cfg {String} emptyText The default text to display in an empty field - placeholder... (defaults to null).
39749 initEvents : function()
39751 if (this.emptyText) {
39752 this.el.attr('placeholder', this.emptyText);
39755 Roo.form.TextField.superclass.initEvents.call(this);
39756 if(this.validationEvent == 'keyup'){
39757 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
39758 this.el.on('keyup', this.filterValidation, this);
39760 else if(this.validationEvent !== false){
39761 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
39764 if(this.selectOnFocus){
39765 this.on("focus", this.preFocus, this);
39767 if (!this.allowLeadingSpace) {
39768 this.on('blur', this.cleanLeadingSpace, this);
39771 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
39772 this.el.on("keypress", this.filterKeys, this);
39775 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
39776 this.el.on("click", this.autoSize, this);
39778 if(this.el.is('input[type=password]') && Roo.isSafari){
39779 this.el.on('keydown', this.SafariOnKeyDown, this);
39783 processValue : function(value){
39784 if(this.stripCharsRe){
39785 var newValue = value.replace(this.stripCharsRe, '');
39786 if(newValue !== value){
39787 this.setRawValue(newValue);
39794 filterValidation : function(e){
39795 if(!e.isNavKeyPress()){
39796 this.validationTask.delay(this.validationDelay);
39801 onKeyUp : function(e){
39802 if(!e.isNavKeyPress()){
39806 // private - clean the leading white space
39807 cleanLeadingSpace : function(e)
39809 if ( this.inputType == 'file') {
39813 this.setValue((this.getValue() + '').replace(/^\s+/,''));
39816 * Resets the current field value to the originally-loaded value and clears any validation messages.
39819 reset : function(){
39820 Roo.form.TextField.superclass.reset.call(this);
39824 preFocus : function(){
39826 if(this.selectOnFocus){
39827 this.el.dom.select();
39833 filterKeys : function(e){
39834 var k = e.getKey();
39835 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
39838 var c = e.getCharCode(), cc = String.fromCharCode(c);
39839 if(Roo.isIE && (e.isSpecialKey() || !cc)){
39842 if(!this.maskRe.test(cc)){
39847 setValue : function(v){
39849 Roo.form.TextField.superclass.setValue.apply(this, arguments);
39855 * Validates a value according to the field's validation rules and marks the field as invalid
39856 * if the validation fails
39857 * @param {Mixed} value The value to validate
39858 * @return {Boolean} True if the value is valid, else false
39860 validateValue : function(value){
39861 if(value.length < 1) { // if it's blank
39862 if(this.allowBlank){
39863 this.clearInvalid();
39866 this.markInvalid(this.blankText);
39870 if(value.length < this.minLength){
39871 this.markInvalid(String.format(this.minLengthText, this.minLength));
39874 if(value.length > this.maxLength){
39875 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
39879 var vt = Roo.form.VTypes;
39880 if(!vt[this.vtype](value, this)){
39881 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
39885 if(typeof this.validator == "function"){
39886 var msg = this.validator(value);
39888 this.markInvalid(msg);
39892 if(this.regex && !this.regex.test(value)){
39893 this.markInvalid(this.regexText);
39900 * Selects text in this field
39901 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
39902 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
39904 selectText : function(start, end){
39905 var v = this.getRawValue();
39907 start = start === undefined ? 0 : start;
39908 end = end === undefined ? v.length : end;
39909 var d = this.el.dom;
39910 if(d.setSelectionRange){
39911 d.setSelectionRange(start, end);
39912 }else if(d.createTextRange){
39913 var range = d.createTextRange();
39914 range.moveStart("character", start);
39915 range.moveEnd("character", v.length-end);
39922 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
39923 * This only takes effect if grow = true, and fires the autosize event.
39925 autoSize : function(){
39926 if(!this.grow || !this.rendered){
39930 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
39933 var v = el.dom.value;
39934 var d = document.createElement('div');
39935 d.appendChild(document.createTextNode(v));
39939 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
39940 this.el.setWidth(w);
39941 this.fireEvent("autosize", this, w);
39945 SafariOnKeyDown : function(event)
39947 // this is a workaround for a password hang bug on chrome/ webkit.
39949 var isSelectAll = false;
39951 if(this.el.dom.selectionEnd > 0){
39952 isSelectAll = (this.el.dom.selectionEnd - this.el.dom.selectionStart - this.getValue().length == 0) ? true : false;
39954 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
39955 event.preventDefault();
39960 if(isSelectAll && event.getCharCode() > 31){ // backspace and delete key
39962 event.preventDefault();
39963 // this is very hacky as keydown always get's upper case.
39965 var cc = String.fromCharCode(event.getCharCode());
39968 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
39976 * Ext JS Library 1.1.1
39977 * Copyright(c) 2006-2007, Ext JS, LLC.
39979 * Originally Released Under LGPL - original licence link has changed is not relivant.
39982 * <script type="text/javascript">
39986 * @class Roo.form.Hidden
39987 * @extends Roo.form.TextField
39988 * Simple Hidden element used on forms
39990 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
39993 * Creates a new Hidden form element.
39994 * @param {Object} config Configuration options
39999 // easy hidden field...
40000 Roo.form.Hidden = function(config){
40001 Roo.form.Hidden.superclass.constructor.call(this, config);
40004 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
40006 inputType: 'hidden',
40009 labelSeparator: '',
40011 itemCls : 'x-form-item-display-none'
40019 * Ext JS Library 1.1.1
40020 * Copyright(c) 2006-2007, Ext JS, LLC.
40022 * Originally Released Under LGPL - original licence link has changed is not relivant.
40025 * <script type="text/javascript">
40029 * @class Roo.form.TriggerField
40030 * @extends Roo.form.TextField
40031 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
40032 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
40033 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
40034 * for which you can provide a custom implementation. For example:
40036 var trigger = new Roo.form.TriggerField();
40037 trigger.onTriggerClick = myTriggerFn;
40038 trigger.applyTo('my-field');
40041 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
40042 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
40043 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
40044 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
40046 * Create a new TriggerField.
40047 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
40048 * to the base TextField)
40050 Roo.form.TriggerField = function(config){
40051 this.mimicing = false;
40052 Roo.form.TriggerField.superclass.constructor.call(this, config);
40055 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
40057 * @cfg {String} triggerClass A CSS class to apply to the trigger
40060 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
40061 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
40063 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "new-password"},
40065 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
40069 /** @cfg {Boolean} grow @hide */
40070 /** @cfg {Number} growMin @hide */
40071 /** @cfg {Number} growMax @hide */
40077 autoSize: Roo.emptyFn,
40081 deferHeight : true,
40084 actionMode : 'wrap',
40086 onResize : function(w, h){
40087 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
40088 if(typeof w == 'number'){
40089 var x = w - this.trigger.getWidth();
40090 this.el.setWidth(this.adjustWidth('input', x));
40091 this.trigger.setStyle('left', x+'px');
40096 adjustSize : Roo.BoxComponent.prototype.adjustSize,
40099 getResizeEl : function(){
40104 getPositionEl : function(){
40109 alignErrorIcon : function(){
40110 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
40114 onRender : function(ct, position){
40115 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
40116 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
40117 this.trigger = this.wrap.createChild(this.triggerConfig ||
40118 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
40119 if(this.hideTrigger){
40120 this.trigger.setDisplayed(false);
40122 this.initTrigger();
40124 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
40129 initTrigger : function(){
40130 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
40131 this.trigger.addClassOnOver('x-form-trigger-over');
40132 this.trigger.addClassOnClick('x-form-trigger-click');
40136 onDestroy : function(){
40138 this.trigger.removeAllListeners();
40139 this.trigger.remove();
40142 this.wrap.remove();
40144 Roo.form.TriggerField.superclass.onDestroy.call(this);
40148 onFocus : function(){
40149 Roo.form.TriggerField.superclass.onFocus.call(this);
40150 if(!this.mimicing){
40151 this.wrap.addClass('x-trigger-wrap-focus');
40152 this.mimicing = true;
40153 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
40154 if(this.monitorTab){
40155 this.el.on("keydown", this.checkTab, this);
40161 checkTab : function(e){
40162 if(e.getKey() == e.TAB){
40163 this.triggerBlur();
40168 onBlur : function(){
40173 mimicBlur : function(e, t){
40174 if(!this.wrap.contains(t) && this.validateBlur()){
40175 this.triggerBlur();
40180 triggerBlur : function(){
40181 this.mimicing = false;
40182 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
40183 if(this.monitorTab){
40184 this.el.un("keydown", this.checkTab, this);
40186 this.wrap.removeClass('x-trigger-wrap-focus');
40187 Roo.form.TriggerField.superclass.onBlur.call(this);
40191 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
40192 validateBlur : function(e, t){
40197 onDisable : function(){
40198 Roo.form.TriggerField.superclass.onDisable.call(this);
40200 this.wrap.addClass('x-item-disabled');
40205 onEnable : function(){
40206 Roo.form.TriggerField.superclass.onEnable.call(this);
40208 this.wrap.removeClass('x-item-disabled');
40213 onShow : function(){
40214 var ae = this.getActionEl();
40217 ae.dom.style.display = '';
40218 ae.dom.style.visibility = 'visible';
40224 onHide : function(){
40225 var ae = this.getActionEl();
40226 ae.dom.style.display = 'none';
40230 * The function that should handle the trigger's click event. This method does nothing by default until overridden
40231 * by an implementing function.
40233 * @param {EventObject} e
40235 onTriggerClick : Roo.emptyFn
40238 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
40239 // to be extended by an implementing class. For an example of implementing this class, see the custom
40240 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
40241 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
40242 initComponent : function(){
40243 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
40245 this.triggerConfig = {
40246 tag:'span', cls:'x-form-twin-triggers', cn:[
40247 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
40248 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
40252 getTrigger : function(index){
40253 return this.triggers[index];
40256 initTrigger : function(){
40257 var ts = this.trigger.select('.x-form-trigger', true);
40258 this.wrap.setStyle('overflow', 'hidden');
40259 var triggerField = this;
40260 ts.each(function(t, all, index){
40261 t.hide = function(){
40262 var w = triggerField.wrap.getWidth();
40263 this.dom.style.display = 'none';
40264 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
40266 t.show = function(){
40267 var w = triggerField.wrap.getWidth();
40268 this.dom.style.display = '';
40269 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
40271 var triggerIndex = 'Trigger'+(index+1);
40273 if(this['hide'+triggerIndex]){
40274 t.dom.style.display = 'none';
40276 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
40277 t.addClassOnOver('x-form-trigger-over');
40278 t.addClassOnClick('x-form-trigger-click');
40280 this.triggers = ts.elements;
40283 onTrigger1Click : Roo.emptyFn,
40284 onTrigger2Click : Roo.emptyFn
40287 * Ext JS Library 1.1.1
40288 * Copyright(c) 2006-2007, Ext JS, LLC.
40290 * Originally Released Under LGPL - original licence link has changed is not relivant.
40293 * <script type="text/javascript">
40297 * @class Roo.form.TextArea
40298 * @extends Roo.form.TextField
40299 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
40300 * support for auto-sizing.
40302 * Creates a new TextArea
40303 * @param {Object} config Configuration options
40305 Roo.form.TextArea = function(config){
40306 Roo.form.TextArea.superclass.constructor.call(this, config);
40307 // these are provided exchanges for backwards compat
40308 // minHeight/maxHeight were replaced by growMin/growMax to be
40309 // compatible with TextField growing config values
40310 if(this.minHeight !== undefined){
40311 this.growMin = this.minHeight;
40313 if(this.maxHeight !== undefined){
40314 this.growMax = this.maxHeight;
40318 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
40320 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
40324 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
40328 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
40329 * in the field (equivalent to setting overflow: hidden, defaults to false)
40331 preventScrollbars: false,
40333 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
40334 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
40338 onRender : function(ct, position){
40340 this.defaultAutoCreate = {
40342 style:"width:300px;height:60px;",
40343 autocomplete: "new-password"
40346 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
40348 this.textSizeEl = Roo.DomHelper.append(document.body, {
40349 tag: "pre", cls: "x-form-grow-sizer"
40351 if(this.preventScrollbars){
40352 this.el.setStyle("overflow", "hidden");
40354 this.el.setHeight(this.growMin);
40358 onDestroy : function(){
40359 if(this.textSizeEl){
40360 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
40362 Roo.form.TextArea.superclass.onDestroy.call(this);
40366 onKeyUp : function(e){
40367 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
40373 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
40374 * This only takes effect if grow = true, and fires the autosize event if the height changes.
40376 autoSize : function(){
40377 if(!this.grow || !this.textSizeEl){
40381 var v = el.dom.value;
40382 var ts = this.textSizeEl;
40385 ts.appendChild(document.createTextNode(v));
40388 Roo.fly(ts).setWidth(this.el.getWidth());
40390 v = "  ";
40393 v = v.replace(/\n/g, '<p> </p>');
40395 v += " \n ";
40398 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
40399 if(h != this.lastHeight){
40400 this.lastHeight = h;
40401 this.el.setHeight(h);
40402 this.fireEvent("autosize", this, h);
40407 * Ext JS Library 1.1.1
40408 * Copyright(c) 2006-2007, Ext JS, LLC.
40410 * Originally Released Under LGPL - original licence link has changed is not relivant.
40413 * <script type="text/javascript">
40418 * @class Roo.form.NumberField
40419 * @extends Roo.form.TextField
40420 * Numeric text field that provides automatic keystroke filtering and numeric validation.
40422 * Creates a new NumberField
40423 * @param {Object} config Configuration options
40425 Roo.form.NumberField = function(config){
40426 Roo.form.NumberField.superclass.constructor.call(this, config);
40429 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
40431 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
40433 fieldClass: "x-form-field x-form-num-field",
40435 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
40437 allowDecimals : true,
40439 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
40441 decimalSeparator : ".",
40443 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
40445 decimalPrecision : 2,
40447 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
40449 allowNegative : true,
40451 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
40453 minValue : Number.NEGATIVE_INFINITY,
40455 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
40457 maxValue : Number.MAX_VALUE,
40459 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
40461 minText : "The minimum value for this field is {0}",
40463 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
40465 maxText : "The maximum value for this field is {0}",
40467 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
40468 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
40470 nanText : "{0} is not a valid number",
40473 initEvents : function(){
40474 Roo.form.NumberField.superclass.initEvents.call(this);
40475 var allowed = "0123456789";
40476 if(this.allowDecimals){
40477 allowed += this.decimalSeparator;
40479 if(this.allowNegative){
40482 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
40483 var keyPress = function(e){
40484 var k = e.getKey();
40485 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40488 var c = e.getCharCode();
40489 if(allowed.indexOf(String.fromCharCode(c)) === -1){
40493 this.el.on("keypress", keyPress, this);
40497 validateValue : function(value){
40498 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
40501 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
40504 var num = this.parseValue(value);
40506 this.markInvalid(String.format(this.nanText, value));
40509 if(num < this.minValue){
40510 this.markInvalid(String.format(this.minText, this.minValue));
40513 if(num > this.maxValue){
40514 this.markInvalid(String.format(this.maxText, this.maxValue));
40520 getValue : function(){
40521 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
40525 parseValue : function(value){
40526 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
40527 return isNaN(value) ? '' : value;
40531 fixPrecision : function(value){
40532 var nan = isNaN(value);
40533 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
40534 return nan ? '' : value;
40536 return parseFloat(value).toFixed(this.decimalPrecision);
40539 setValue : function(v){
40540 v = this.fixPrecision(v);
40541 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
40545 decimalPrecisionFcn : function(v){
40546 return Math.floor(v);
40549 beforeBlur : function(){
40550 var v = this.parseValue(this.getRawValue());
40557 * Ext JS Library 1.1.1
40558 * Copyright(c) 2006-2007, Ext JS, LLC.
40560 * Originally Released Under LGPL - original licence link has changed is not relivant.
40563 * <script type="text/javascript">
40567 * @class Roo.form.DateField
40568 * @extends Roo.form.TriggerField
40569 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
40571 * Create a new DateField
40572 * @param {Object} config
40574 Roo.form.DateField = function(config)
40576 Roo.form.DateField.superclass.constructor.call(this, config);
40582 * Fires when a date is selected
40583 * @param {Roo.form.DateField} combo This combo box
40584 * @param {Date} date The date selected
40591 if(typeof this.minValue == "string") {
40592 this.minValue = this.parseDate(this.minValue);
40594 if(typeof this.maxValue == "string") {
40595 this.maxValue = this.parseDate(this.maxValue);
40597 this.ddMatch = null;
40598 if(this.disabledDates){
40599 var dd = this.disabledDates;
40601 for(var i = 0; i < dd.length; i++){
40603 if(i != dd.length-1) {
40607 this.ddMatch = new RegExp(re + ")");
40611 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
40613 * @cfg {String} format
40614 * The default date format string which can be overriden for localization support. The format must be
40615 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
40619 * @cfg {String} altFormats
40620 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
40621 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
40623 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
40625 * @cfg {Array} disabledDays
40626 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
40628 disabledDays : null,
40630 * @cfg {String} disabledDaysText
40631 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
40633 disabledDaysText : "Disabled",
40635 * @cfg {Array} disabledDates
40636 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
40637 * expression so they are very powerful. Some examples:
40639 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
40640 * <li>["03/08", "09/16"] would disable those days for every year</li>
40641 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
40642 * <li>["03/../2006"] would disable every day in March 2006</li>
40643 * <li>["^03"] would disable every day in every March</li>
40645 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
40646 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
40648 disabledDates : null,
40650 * @cfg {String} disabledDatesText
40651 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
40653 disabledDatesText : "Disabled",
40655 * @cfg {Date/String} minValue
40656 * The minimum allowed date. Can be either a Javascript date object or a string date in a
40657 * valid format (defaults to null).
40661 * @cfg {Date/String} maxValue
40662 * The maximum allowed date. Can be either a Javascript date object or a string date in a
40663 * valid format (defaults to null).
40667 * @cfg {String} minText
40668 * The error text to display when the date in the cell is before minValue (defaults to
40669 * 'The date in this field must be after {minValue}').
40671 minText : "The date in this field must be equal to or after {0}",
40673 * @cfg {String} maxText
40674 * The error text to display when the date in the cell is after maxValue (defaults to
40675 * 'The date in this field must be before {maxValue}').
40677 maxText : "The date in this field must be equal to or before {0}",
40679 * @cfg {String} invalidText
40680 * The error text to display when the date in the field is invalid (defaults to
40681 * '{value} is not a valid date - it must be in the format {format}').
40683 invalidText : "{0} is not a valid date - it must be in the format {1}",
40685 * @cfg {String} triggerClass
40686 * An additional CSS class used to style the trigger button. The trigger will always get the
40687 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
40688 * which displays a calendar icon).
40690 triggerClass : 'x-form-date-trigger',
40694 * @cfg {Boolean} useIso
40695 * if enabled, then the date field will use a hidden field to store the
40696 * real value as iso formated date. default (false)
40700 * @cfg {String/Object} autoCreate
40701 * A DomHelper element spec, or true for a default element spec (defaults to
40702 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
40705 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
40708 hiddenField: false,
40710 onRender : function(ct, position)
40712 Roo.form.DateField.superclass.onRender.call(this, ct, position);
40714 //this.el.dom.removeAttribute('name');
40715 Roo.log("Changing name?");
40716 this.el.dom.setAttribute('name', this.name + '____hidden___' );
40717 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
40719 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
40720 // prevent input submission
40721 this.hiddenName = this.name;
40728 validateValue : function(value)
40730 value = this.formatDate(value);
40731 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
40732 Roo.log('super failed');
40735 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
40738 var svalue = value;
40739 value = this.parseDate(value);
40741 Roo.log('parse date failed' + svalue);
40742 this.markInvalid(String.format(this.invalidText, svalue, this.format));
40745 var time = value.getTime();
40746 if(this.minValue && time < this.minValue.getTime()){
40747 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
40750 if(this.maxValue && time > this.maxValue.getTime()){
40751 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
40754 if(this.disabledDays){
40755 var day = value.getDay();
40756 for(var i = 0; i < this.disabledDays.length; i++) {
40757 if(day === this.disabledDays[i]){
40758 this.markInvalid(this.disabledDaysText);
40763 var fvalue = this.formatDate(value);
40764 if(this.ddMatch && this.ddMatch.test(fvalue)){
40765 this.markInvalid(String.format(this.disabledDatesText, fvalue));
40772 // Provides logic to override the default TriggerField.validateBlur which just returns true
40773 validateBlur : function(){
40774 return !this.menu || !this.menu.isVisible();
40777 getName: function()
40779 // returns hidden if it's set..
40780 if (!this.rendered) {return ''};
40781 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
40786 * Returns the current date value of the date field.
40787 * @return {Date} The date value
40789 getValue : function(){
40791 return this.hiddenField ?
40792 this.hiddenField.value :
40793 this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
40797 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
40798 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
40799 * (the default format used is "m/d/y").
40802 //All of these calls set the same date value (May 4, 2006)
40804 //Pass a date object:
40805 var dt = new Date('5/4/06');
40806 dateField.setValue(dt);
40808 //Pass a date string (default format):
40809 dateField.setValue('5/4/06');
40811 //Pass a date string (custom format):
40812 dateField.format = 'Y-m-d';
40813 dateField.setValue('2006-5-4');
40815 * @param {String/Date} date The date or valid date string
40817 setValue : function(date){
40818 if (this.hiddenField) {
40819 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
40821 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
40822 // make sure the value field is always stored as a date..
40823 this.value = this.parseDate(date);
40829 parseDate : function(value){
40830 if(!value || value instanceof Date){
40833 var v = Date.parseDate(value, this.format);
40834 if (!v && this.useIso) {
40835 v = Date.parseDate(value, 'Y-m-d');
40837 if(!v && this.altFormats){
40838 if(!this.altFormatsArray){
40839 this.altFormatsArray = this.altFormats.split("|");
40841 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
40842 v = Date.parseDate(value, this.altFormatsArray[i]);
40849 formatDate : function(date, fmt){
40850 return (!date || !(date instanceof Date)) ?
40851 date : date.dateFormat(fmt || this.format);
40856 select: function(m, d){
40859 this.fireEvent('select', this, d);
40861 show : function(){ // retain focus styling
40865 this.focus.defer(10, this);
40866 var ml = this.menuListeners;
40867 this.menu.un("select", ml.select, this);
40868 this.menu.un("show", ml.show, this);
40869 this.menu.un("hide", ml.hide, this);
40874 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
40875 onTriggerClick : function(){
40879 if(this.menu == null){
40880 this.menu = new Roo.menu.DateMenu();
40882 Roo.apply(this.menu.picker, {
40883 showClear: this.allowBlank,
40884 minDate : this.minValue,
40885 maxDate : this.maxValue,
40886 disabledDatesRE : this.ddMatch,
40887 disabledDatesText : this.disabledDatesText,
40888 disabledDays : this.disabledDays,
40889 disabledDaysText : this.disabledDaysText,
40890 format : this.useIso ? 'Y-m-d' : this.format,
40891 minText : String.format(this.minText, this.formatDate(this.minValue)),
40892 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
40894 this.menu.on(Roo.apply({}, this.menuListeners, {
40897 this.menu.picker.setValue(this.getValue() || new Date());
40898 this.menu.show(this.el, "tl-bl?");
40901 beforeBlur : function(){
40902 var v = this.parseDate(this.getRawValue());
40912 isDirty : function() {
40913 if(this.disabled) {
40917 if(typeof(this.startValue) === 'undefined'){
40921 return String(this.getValue()) !== String(this.startValue);
40925 cleanLeadingSpace : function(e)
40932 * Ext JS Library 1.1.1
40933 * Copyright(c) 2006-2007, Ext JS, LLC.
40935 * Originally Released Under LGPL - original licence link has changed is not relivant.
40938 * <script type="text/javascript">
40942 * @class Roo.form.MonthField
40943 * @extends Roo.form.TriggerField
40944 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
40946 * Create a new MonthField
40947 * @param {Object} config
40949 Roo.form.MonthField = function(config){
40951 Roo.form.MonthField.superclass.constructor.call(this, config);
40957 * Fires when a date is selected
40958 * @param {Roo.form.MonthFieeld} combo This combo box
40959 * @param {Date} date The date selected
40966 if(typeof this.minValue == "string") {
40967 this.minValue = this.parseDate(this.minValue);
40969 if(typeof this.maxValue == "string") {
40970 this.maxValue = this.parseDate(this.maxValue);
40972 this.ddMatch = null;
40973 if(this.disabledDates){
40974 var dd = this.disabledDates;
40976 for(var i = 0; i < dd.length; i++){
40978 if(i != dd.length-1) {
40982 this.ddMatch = new RegExp(re + ")");
40986 Roo.extend(Roo.form.MonthField, Roo.form.TriggerField, {
40988 * @cfg {String} format
40989 * The default date format string which can be overriden for localization support. The format must be
40990 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
40994 * @cfg {String} altFormats
40995 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
40996 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
40998 altFormats : "M Y|m/Y|m-y|m-Y|my|mY",
41000 * @cfg {Array} disabledDays
41001 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
41003 disabledDays : [0,1,2,3,4,5,6],
41005 * @cfg {String} disabledDaysText
41006 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
41008 disabledDaysText : "Disabled",
41010 * @cfg {Array} disabledDates
41011 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
41012 * expression so they are very powerful. Some examples:
41014 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
41015 * <li>["03/08", "09/16"] would disable those days for every year</li>
41016 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
41017 * <li>["03/../2006"] would disable every day in March 2006</li>
41018 * <li>["^03"] would disable every day in every March</li>
41020 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
41021 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
41023 disabledDates : null,
41025 * @cfg {String} disabledDatesText
41026 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
41028 disabledDatesText : "Disabled",
41030 * @cfg {Date/String} minValue
41031 * The minimum allowed date. Can be either a Javascript date object or a string date in a
41032 * valid format (defaults to null).
41036 * @cfg {Date/String} maxValue
41037 * The maximum allowed date. Can be either a Javascript date object or a string date in a
41038 * valid format (defaults to null).
41042 * @cfg {String} minText
41043 * The error text to display when the date in the cell is before minValue (defaults to
41044 * 'The date in this field must be after {minValue}').
41046 minText : "The date in this field must be equal to or after {0}",
41048 * @cfg {String} maxTextf
41049 * The error text to display when the date in the cell is after maxValue (defaults to
41050 * 'The date in this field must be before {maxValue}').
41052 maxText : "The date in this field must be equal to or before {0}",
41054 * @cfg {String} invalidText
41055 * The error text to display when the date in the field is invalid (defaults to
41056 * '{value} is not a valid date - it must be in the format {format}').
41058 invalidText : "{0} is not a valid date - it must be in the format {1}",
41060 * @cfg {String} triggerClass
41061 * An additional CSS class used to style the trigger button. The trigger will always get the
41062 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
41063 * which displays a calendar icon).
41065 triggerClass : 'x-form-date-trigger',
41069 * @cfg {Boolean} useIso
41070 * if enabled, then the date field will use a hidden field to store the
41071 * real value as iso formated date. default (true)
41075 * @cfg {String/Object} autoCreate
41076 * A DomHelper element spec, or true for a default element spec (defaults to
41077 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
41080 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "new-password"},
41083 hiddenField: false,
41085 hideMonthPicker : false,
41087 onRender : function(ct, position)
41089 Roo.form.MonthField.superclass.onRender.call(this, ct, position);
41091 this.el.dom.removeAttribute('name');
41092 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
41094 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
41095 // prevent input submission
41096 this.hiddenName = this.name;
41103 validateValue : function(value)
41105 value = this.formatDate(value);
41106 if(!Roo.form.MonthField.superclass.validateValue.call(this, value)){
41109 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
41112 var svalue = value;
41113 value = this.parseDate(value);
41115 this.markInvalid(String.format(this.invalidText, svalue, this.format));
41118 var time = value.getTime();
41119 if(this.minValue && time < this.minValue.getTime()){
41120 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
41123 if(this.maxValue && time > this.maxValue.getTime()){
41124 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
41127 /*if(this.disabledDays){
41128 var day = value.getDay();
41129 for(var i = 0; i < this.disabledDays.length; i++) {
41130 if(day === this.disabledDays[i]){
41131 this.markInvalid(this.disabledDaysText);
41137 var fvalue = this.formatDate(value);
41138 /*if(this.ddMatch && this.ddMatch.test(fvalue)){
41139 this.markInvalid(String.format(this.disabledDatesText, fvalue));
41147 // Provides logic to override the default TriggerField.validateBlur which just returns true
41148 validateBlur : function(){
41149 return !this.menu || !this.menu.isVisible();
41153 * Returns the current date value of the date field.
41154 * @return {Date} The date value
41156 getValue : function(){
41160 return this.hiddenField ?
41161 this.hiddenField.value :
41162 this.parseDate(Roo.form.MonthField.superclass.getValue.call(this)) || "";
41166 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
41167 * date, using MonthField.format as the date format, according to the same rules as {@link Date#parseDate}
41168 * (the default format used is "m/d/y").
41171 //All of these calls set the same date value (May 4, 2006)
41173 //Pass a date object:
41174 var dt = new Date('5/4/06');
41175 monthField.setValue(dt);
41177 //Pass a date string (default format):
41178 monthField.setValue('5/4/06');
41180 //Pass a date string (custom format):
41181 monthField.format = 'Y-m-d';
41182 monthField.setValue('2006-5-4');
41184 * @param {String/Date} date The date or valid date string
41186 setValue : function(date){
41187 Roo.log('month setValue' + date);
41188 // can only be first of month..
41190 var val = this.parseDate(date);
41192 if (this.hiddenField) {
41193 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
41195 Roo.form.MonthField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
41196 this.value = this.parseDate(date);
41200 parseDate : function(value){
41201 if(!value || value instanceof Date){
41202 value = value ? Date.parseDate(value.format('Y-m') + '-01', 'Y-m-d') : null;
41205 var v = Date.parseDate(value, this.format);
41206 if (!v && this.useIso) {
41207 v = Date.parseDate(value, 'Y-m-d');
41211 v = Date.parseDate(v.format('Y-m') +'-01', 'Y-m-d');
41215 if(!v && this.altFormats){
41216 if(!this.altFormatsArray){
41217 this.altFormatsArray = this.altFormats.split("|");
41219 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
41220 v = Date.parseDate(value, this.altFormatsArray[i]);
41227 formatDate : function(date, fmt){
41228 return (!date || !(date instanceof Date)) ?
41229 date : date.dateFormat(fmt || this.format);
41234 select: function(m, d){
41236 this.fireEvent('select', this, d);
41238 show : function(){ // retain focus styling
41242 this.focus.defer(10, this);
41243 var ml = this.menuListeners;
41244 this.menu.un("select", ml.select, this);
41245 this.menu.un("show", ml.show, this);
41246 this.menu.un("hide", ml.hide, this);
41250 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
41251 onTriggerClick : function(){
41255 if(this.menu == null){
41256 this.menu = new Roo.menu.DateMenu();
41260 Roo.apply(this.menu.picker, {
41262 showClear: this.allowBlank,
41263 minDate : this.minValue,
41264 maxDate : this.maxValue,
41265 disabledDatesRE : this.ddMatch,
41266 disabledDatesText : this.disabledDatesText,
41268 format : this.useIso ? 'Y-m-d' : this.format,
41269 minText : String.format(this.minText, this.formatDate(this.minValue)),
41270 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
41273 this.menu.on(Roo.apply({}, this.menuListeners, {
41281 // hide month picker get's called when we called by 'before hide';
41283 var ignorehide = true;
41284 p.hideMonthPicker = function(disableAnim){
41288 if(this.monthPicker){
41289 Roo.log("hideMonthPicker called");
41290 if(disableAnim === true){
41291 this.monthPicker.hide();
41293 this.monthPicker.slideOut('t', {duration:.2});
41294 p.setValue(new Date(m.picker.mpSelYear, m.picker.mpSelMonth, 1));
41295 p.fireEvent("select", this, this.value);
41301 Roo.log('picker set value');
41302 Roo.log(this.getValue());
41303 p.setValue(this.getValue() ? this.parseDate(this.getValue()) : new Date());
41304 m.show(this.el, 'tl-bl?');
41305 ignorehide = false;
41306 // this will trigger hideMonthPicker..
41309 // hidden the day picker
41310 Roo.select('.x-date-picker table', true).first().dom.style.visibility = "hidden";
41316 p.showMonthPicker.defer(100, p);
41322 beforeBlur : function(){
41323 var v = this.parseDate(this.getRawValue());
41329 /** @cfg {Boolean} grow @hide */
41330 /** @cfg {Number} growMin @hide */
41331 /** @cfg {Number} growMax @hide */
41338 * Ext JS Library 1.1.1
41339 * Copyright(c) 2006-2007, Ext JS, LLC.
41341 * Originally Released Under LGPL - original licence link has changed is not relivant.
41344 * <script type="text/javascript">
41349 * @class Roo.form.ComboBox
41350 * @extends Roo.form.TriggerField
41351 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
41353 * Create a new ComboBox.
41354 * @param {Object} config Configuration options
41356 Roo.form.ComboBox = function(config){
41357 Roo.form.ComboBox.superclass.constructor.call(this, config);
41361 * Fires when the dropdown list is expanded
41362 * @param {Roo.form.ComboBox} combo This combo box
41367 * Fires when the dropdown list is collapsed
41368 * @param {Roo.form.ComboBox} combo This combo box
41372 * @event beforeselect
41373 * Fires before a list item is selected. Return false to cancel the selection.
41374 * @param {Roo.form.ComboBox} combo This combo box
41375 * @param {Roo.data.Record} record The data record returned from the underlying store
41376 * @param {Number} index The index of the selected item in the dropdown list
41378 'beforeselect' : true,
41381 * Fires when a list item is selected
41382 * @param {Roo.form.ComboBox} combo This combo box
41383 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
41384 * @param {Number} index The index of the selected item in the dropdown list
41388 * @event beforequery
41389 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
41390 * The event object passed has these properties:
41391 * @param {Roo.form.ComboBox} combo This combo box
41392 * @param {String} query The query
41393 * @param {Boolean} forceAll true to force "all" query
41394 * @param {Boolean} cancel true to cancel the query
41395 * @param {Object} e The query event object
41397 'beforequery': true,
41400 * Fires when the 'add' icon is pressed (add a listener to enable add button)
41401 * @param {Roo.form.ComboBox} combo This combo box
41406 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
41407 * @param {Roo.form.ComboBox} combo This combo box
41408 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
41414 if(this.transform){
41415 this.allowDomMove = false;
41416 var s = Roo.getDom(this.transform);
41417 if(!this.hiddenName){
41418 this.hiddenName = s.name;
41421 this.mode = 'local';
41422 var d = [], opts = s.options;
41423 for(var i = 0, len = opts.length;i < len; i++){
41425 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
41427 this.value = value;
41429 d.push([value, o.text]);
41431 this.store = new Roo.data.SimpleStore({
41433 fields: ['value', 'text'],
41436 this.valueField = 'value';
41437 this.displayField = 'text';
41439 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
41440 if(!this.lazyRender){
41441 this.target = true;
41442 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
41443 s.parentNode.removeChild(s); // remove it
41444 this.render(this.el.parentNode);
41446 s.parentNode.removeChild(s); // remove it
41451 this.store = Roo.factory(this.store, Roo.data);
41454 this.selectedIndex = -1;
41455 if(this.mode == 'local'){
41456 if(config.queryDelay === undefined){
41457 this.queryDelay = 10;
41459 if(config.minChars === undefined){
41465 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
41467 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
41470 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
41471 * rendering into an Roo.Editor, defaults to false)
41474 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
41475 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
41478 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
41481 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
41482 * the dropdown list (defaults to undefined, with no header element)
41486 * @cfg {String/Roo.Template} tpl The template to use to render the output
41490 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
41492 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
41494 listWidth: undefined,
41496 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
41497 * mode = 'remote' or 'text' if mode = 'local')
41499 displayField: undefined,
41501 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
41502 * mode = 'remote' or 'value' if mode = 'local').
41503 * Note: use of a valueField requires the user make a selection
41504 * in order for a value to be mapped.
41506 valueField: undefined,
41510 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
41511 * field's data value (defaults to the underlying DOM element's name)
41513 hiddenName: undefined,
41515 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
41519 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
41521 selectedClass: 'x-combo-selected',
41523 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
41524 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
41525 * which displays a downward arrow icon).
41527 triggerClass : 'x-form-arrow-trigger',
41529 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
41533 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
41534 * anchor positions (defaults to 'tl-bl')
41536 listAlign: 'tl-bl?',
41538 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
41542 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
41543 * query specified by the allQuery config option (defaults to 'query')
41545 triggerAction: 'query',
41547 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
41548 * (defaults to 4, does not apply if editable = false)
41552 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
41553 * delay (typeAheadDelay) if it matches a known value (defaults to false)
41557 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
41558 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
41562 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
41563 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
41567 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
41568 * when editable = true (defaults to false)
41570 selectOnFocus:false,
41572 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
41574 queryParam: 'query',
41576 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
41577 * when mode = 'remote' (defaults to 'Loading...')
41579 loadingText: 'Loading...',
41581 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
41585 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
41589 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
41590 * traditional select (defaults to true)
41594 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
41598 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
41602 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
41603 * listWidth has a higher value)
41607 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
41608 * allow the user to set arbitrary text into the field (defaults to false)
41610 forceSelection:false,
41612 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
41613 * if typeAhead = true (defaults to 250)
41615 typeAheadDelay : 250,
41617 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
41618 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
41620 valueNotFoundText : undefined,
41622 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
41624 blockFocus : false,
41627 * @cfg {Boolean} disableClear Disable showing of clear button.
41629 disableClear : false,
41631 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
41633 alwaysQuery : false,
41639 // element that contains real text value.. (when hidden is used..)
41642 onRender : function(ct, position)
41644 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
41646 if(this.hiddenName){
41647 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
41649 this.hiddenField.value =
41650 this.hiddenValue !== undefined ? this.hiddenValue :
41651 this.value !== undefined ? this.value : '';
41653 // prevent input submission
41654 this.el.dom.removeAttribute('name');
41660 this.el.dom.setAttribute('autocomplete', 'off');
41663 var cls = 'x-combo-list';
41665 this.list = new Roo.Layer({
41666 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
41669 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
41670 this.list.setWidth(lw);
41671 this.list.swallowEvent('mousewheel');
41672 this.assetHeight = 0;
41675 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
41676 this.assetHeight += this.header.getHeight();
41679 this.innerList = this.list.createChild({cls:cls+'-inner'});
41680 this.innerList.on('mouseover', this.onViewOver, this);
41681 this.innerList.on('mousemove', this.onViewMove, this);
41682 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
41684 if(this.allowBlank && !this.pageSize && !this.disableClear){
41685 this.footer = this.list.createChild({cls:cls+'-ft'});
41686 this.pageTb = new Roo.Toolbar(this.footer);
41690 this.footer = this.list.createChild({cls:cls+'-ft'});
41691 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
41692 {pageSize: this.pageSize});
41696 if (this.pageTb && this.allowBlank && !this.disableClear) {
41698 this.pageTb.add(new Roo.Toolbar.Fill(), {
41699 cls: 'x-btn-icon x-btn-clear',
41701 handler: function()
41704 _this.clearValue();
41705 _this.onSelect(false, -1);
41710 this.assetHeight += this.footer.getHeight();
41715 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
41718 this.view = new Roo.View(this.innerList, this.tpl, {
41721 selectedClass: this.selectedClass
41724 this.view.on('click', this.onViewClick, this);
41726 this.store.on('beforeload', this.onBeforeLoad, this);
41727 this.store.on('load', this.onLoad, this);
41728 this.store.on('loadexception', this.onLoadException, this);
41730 if(this.resizable){
41731 this.resizer = new Roo.Resizable(this.list, {
41732 pinned:true, handles:'se'
41734 this.resizer.on('resize', function(r, w, h){
41735 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
41736 this.listWidth = w;
41737 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
41738 this.restrictHeight();
41740 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
41742 if(!this.editable){
41743 this.editable = true;
41744 this.setEditable(false);
41748 if (typeof(this.events.add.listeners) != 'undefined') {
41750 this.addicon = this.wrap.createChild(
41751 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
41753 this.addicon.on('click', function(e) {
41754 this.fireEvent('add', this);
41757 if (typeof(this.events.edit.listeners) != 'undefined') {
41759 this.editicon = this.wrap.createChild(
41760 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
41761 if (this.addicon) {
41762 this.editicon.setStyle('margin-left', '40px');
41764 this.editicon.on('click', function(e) {
41766 // we fire even if inothing is selected..
41767 this.fireEvent('edit', this, this.lastData );
41777 initEvents : function(){
41778 Roo.form.ComboBox.superclass.initEvents.call(this);
41780 this.keyNav = new Roo.KeyNav(this.el, {
41781 "up" : function(e){
41782 this.inKeyMode = true;
41786 "down" : function(e){
41787 if(!this.isExpanded()){
41788 this.onTriggerClick();
41790 this.inKeyMode = true;
41795 "enter" : function(e){
41796 this.onViewClick();
41800 "esc" : function(e){
41804 "tab" : function(e){
41805 this.onViewClick(false);
41806 this.fireEvent("specialkey", this, e);
41812 doRelay : function(foo, bar, hname){
41813 if(hname == 'down' || this.scope.isExpanded()){
41814 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
41821 this.queryDelay = Math.max(this.queryDelay || 10,
41822 this.mode == 'local' ? 10 : 250);
41823 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
41824 if(this.typeAhead){
41825 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
41827 if(this.editable !== false){
41828 this.el.on("keyup", this.onKeyUp, this);
41830 if(this.forceSelection){
41831 this.on('blur', this.doForce, this);
41835 onDestroy : function(){
41837 this.view.setStore(null);
41838 this.view.el.removeAllListeners();
41839 this.view.el.remove();
41840 this.view.purgeListeners();
41843 this.list.destroy();
41846 this.store.un('beforeload', this.onBeforeLoad, this);
41847 this.store.un('load', this.onLoad, this);
41848 this.store.un('loadexception', this.onLoadException, this);
41850 Roo.form.ComboBox.superclass.onDestroy.call(this);
41854 fireKey : function(e){
41855 if(e.isNavKeyPress() && !this.list.isVisible()){
41856 this.fireEvent("specialkey", this, e);
41861 onResize: function(w, h){
41862 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
41864 if(typeof w != 'number'){
41865 // we do not handle it!?!?
41868 var tw = this.trigger.getWidth();
41869 tw += this.addicon ? this.addicon.getWidth() : 0;
41870 tw += this.editicon ? this.editicon.getWidth() : 0;
41872 this.el.setWidth( this.adjustWidth('input', x));
41874 this.trigger.setStyle('left', x+'px');
41876 if(this.list && this.listWidth === undefined){
41877 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
41878 this.list.setWidth(lw);
41879 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
41887 * Allow or prevent the user from directly editing the field text. If false is passed,
41888 * the user will only be able to select from the items defined in the dropdown list. This method
41889 * is the runtime equivalent of setting the 'editable' config option at config time.
41890 * @param {Boolean} value True to allow the user to directly edit the field text
41892 setEditable : function(value){
41893 if(value == this.editable){
41896 this.editable = value;
41898 this.el.dom.setAttribute('readOnly', true);
41899 this.el.on('mousedown', this.onTriggerClick, this);
41900 this.el.addClass('x-combo-noedit');
41902 this.el.dom.setAttribute('readOnly', false);
41903 this.el.un('mousedown', this.onTriggerClick, this);
41904 this.el.removeClass('x-combo-noedit');
41909 onBeforeLoad : function(){
41910 if(!this.hasFocus){
41913 this.innerList.update(this.loadingText ?
41914 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
41915 this.restrictHeight();
41916 this.selectedIndex = -1;
41920 onLoad : function(){
41921 if(!this.hasFocus){
41924 if(this.store.getCount() > 0){
41926 this.restrictHeight();
41927 if(this.lastQuery == this.allQuery){
41929 this.el.dom.select();
41931 if(!this.selectByValue(this.value, true)){
41932 this.select(0, true);
41936 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
41937 this.taTask.delay(this.typeAheadDelay);
41941 this.onEmptyResults();
41946 onLoadException : function()
41949 Roo.log(this.store.reader.jsonData);
41950 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
41951 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
41957 onTypeAhead : function(){
41958 if(this.store.getCount() > 0){
41959 var r = this.store.getAt(0);
41960 var newValue = r.data[this.displayField];
41961 var len = newValue.length;
41962 var selStart = this.getRawValue().length;
41963 if(selStart != len){
41964 this.setRawValue(newValue);
41965 this.selectText(selStart, newValue.length);
41971 onSelect : function(record, index){
41972 if(this.fireEvent('beforeselect', this, record, index) !== false){
41973 this.setFromData(index > -1 ? record.data : false);
41975 this.fireEvent('select', this, record, index);
41980 * Returns the currently selected field value or empty string if no value is set.
41981 * @return {String} value The selected value
41983 getValue : function(){
41984 if(this.valueField){
41985 return typeof this.value != 'undefined' ? this.value : '';
41987 return Roo.form.ComboBox.superclass.getValue.call(this);
41991 * Clears any text/value currently set in the field
41993 clearValue : function(){
41994 if(this.hiddenField){
41995 this.hiddenField.value = '';
41998 this.setRawValue('');
41999 this.lastSelectionText = '';
42004 * Sets the specified value into the field. If the value finds a match, the corresponding record text
42005 * will be displayed in the field. If the value does not match the data value of an existing item,
42006 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
42007 * Otherwise the field will be blank (although the value will still be set).
42008 * @param {String} value The value to match
42010 setValue : function(v){
42012 if(this.valueField){
42013 var r = this.findRecord(this.valueField, v);
42015 text = r.data[this.displayField];
42016 }else if(this.valueNotFoundText !== undefined){
42017 text = this.valueNotFoundText;
42020 this.lastSelectionText = text;
42021 if(this.hiddenField){
42022 this.hiddenField.value = v;
42024 Roo.form.ComboBox.superclass.setValue.call(this, text);
42028 * @property {Object} the last set data for the element
42033 * Sets the value of the field based on a object which is related to the record format for the store.
42034 * @param {Object} value the value to set as. or false on reset?
42036 setFromData : function(o){
42037 var dv = ''; // display value
42038 var vv = ''; // value value..
42040 if (this.displayField) {
42041 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
42043 // this is an error condition!!!
42044 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
42047 if(this.valueField){
42048 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
42050 if(this.hiddenField){
42051 this.hiddenField.value = vv;
42053 this.lastSelectionText = dv;
42054 Roo.form.ComboBox.superclass.setValue.call(this, dv);
42058 // no hidden field.. - we store the value in 'value', but still display
42059 // display field!!!!
42060 this.lastSelectionText = dv;
42061 Roo.form.ComboBox.superclass.setValue.call(this, dv);
42067 reset : function(){
42068 // overridden so that last data is reset..
42069 this.setValue(this.resetValue);
42070 this.originalValue = this.getValue();
42071 this.clearInvalid();
42072 this.lastData = false;
42074 this.view.clearSelections();
42078 findRecord : function(prop, value){
42080 if(this.store.getCount() > 0){
42081 this.store.each(function(r){
42082 if(r.data[prop] == value){
42092 getName: function()
42094 // returns hidden if it's set..
42095 if (!this.rendered) {return ''};
42096 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
42100 onViewMove : function(e, t){
42101 this.inKeyMode = false;
42105 onViewOver : function(e, t){
42106 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
42109 var item = this.view.findItemFromChild(t);
42111 var index = this.view.indexOf(item);
42112 this.select(index, false);
42117 onViewClick : function(doFocus)
42119 var index = this.view.getSelectedIndexes()[0];
42120 var r = this.store.getAt(index);
42122 this.onSelect(r, index);
42124 if(doFocus !== false && !this.blockFocus){
42130 restrictHeight : function(){
42131 this.innerList.dom.style.height = '';
42132 var inner = this.innerList.dom;
42133 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
42134 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
42135 this.list.beginUpdate();
42136 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
42137 this.list.alignTo(this.el, this.listAlign);
42138 this.list.endUpdate();
42142 onEmptyResults : function(){
42147 * Returns true if the dropdown list is expanded, else false.
42149 isExpanded : function(){
42150 return this.list.isVisible();
42154 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
42155 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
42156 * @param {String} value The data value of the item to select
42157 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
42158 * selected item if it is not currently in view (defaults to true)
42159 * @return {Boolean} True if the value matched an item in the list, else false
42161 selectByValue : function(v, scrollIntoView){
42162 if(v !== undefined && v !== null){
42163 var r = this.findRecord(this.valueField || this.displayField, v);
42165 this.select(this.store.indexOf(r), scrollIntoView);
42173 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
42174 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
42175 * @param {Number} index The zero-based index of the list item to select
42176 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
42177 * selected item if it is not currently in view (defaults to true)
42179 select : function(index, scrollIntoView){
42180 this.selectedIndex = index;
42181 this.view.select(index);
42182 if(scrollIntoView !== false){
42183 var el = this.view.getNode(index);
42185 this.innerList.scrollChildIntoView(el, false);
42191 selectNext : function(){
42192 var ct = this.store.getCount();
42194 if(this.selectedIndex == -1){
42196 }else if(this.selectedIndex < ct-1){
42197 this.select(this.selectedIndex+1);
42203 selectPrev : function(){
42204 var ct = this.store.getCount();
42206 if(this.selectedIndex == -1){
42208 }else if(this.selectedIndex != 0){
42209 this.select(this.selectedIndex-1);
42215 onKeyUp : function(e){
42216 if(this.editable !== false && !e.isSpecialKey()){
42217 this.lastKey = e.getKey();
42218 this.dqTask.delay(this.queryDelay);
42223 validateBlur : function(){
42224 return !this.list || !this.list.isVisible();
42228 initQuery : function(){
42229 this.doQuery(this.getRawValue());
42233 doForce : function(){
42234 if(this.el.dom.value.length > 0){
42235 this.el.dom.value =
42236 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
42242 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
42243 * query allowing the query action to be canceled if needed.
42244 * @param {String} query The SQL query to execute
42245 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
42246 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
42247 * saved in the current store (defaults to false)
42249 doQuery : function(q, forceAll){
42250 if(q === undefined || q === null){
42255 forceAll: forceAll,
42259 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
42263 forceAll = qe.forceAll;
42264 if(forceAll === true || (q.length >= this.minChars)){
42265 if(this.lastQuery != q || this.alwaysQuery){
42266 this.lastQuery = q;
42267 if(this.mode == 'local'){
42268 this.selectedIndex = -1;
42270 this.store.clearFilter();
42272 this.store.filter(this.displayField, q);
42276 this.store.baseParams[this.queryParam] = q;
42278 params: this.getParams(q)
42283 this.selectedIndex = -1;
42290 getParams : function(q){
42292 //p[this.queryParam] = q;
42295 p.limit = this.pageSize;
42301 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
42303 collapse : function(){
42304 if(!this.isExpanded()){
42308 Roo.get(document).un('mousedown', this.collapseIf, this);
42309 Roo.get(document).un('mousewheel', this.collapseIf, this);
42310 if (!this.editable) {
42311 Roo.get(document).un('keydown', this.listKeyPress, this);
42313 this.fireEvent('collapse', this);
42317 collapseIf : function(e){
42318 if(!e.within(this.wrap) && !e.within(this.list)){
42324 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
42326 expand : function(){
42327 if(this.isExpanded() || !this.hasFocus){
42330 this.list.alignTo(this.el, this.listAlign);
42332 Roo.get(document).on('mousedown', this.collapseIf, this);
42333 Roo.get(document).on('mousewheel', this.collapseIf, this);
42334 if (!this.editable) {
42335 Roo.get(document).on('keydown', this.listKeyPress, this);
42338 this.fireEvent('expand', this);
42342 // Implements the default empty TriggerField.onTriggerClick function
42343 onTriggerClick : function(){
42347 if(this.isExpanded()){
42349 if (!this.blockFocus) {
42354 this.hasFocus = true;
42355 if(this.triggerAction == 'all') {
42356 this.doQuery(this.allQuery, true);
42358 this.doQuery(this.getRawValue());
42360 if (!this.blockFocus) {
42365 listKeyPress : function(e)
42367 //Roo.log('listkeypress');
42368 // scroll to first matching element based on key pres..
42369 if (e.isSpecialKey()) {
42372 var k = String.fromCharCode(e.getKey()).toUpperCase();
42375 var csel = this.view.getSelectedNodes();
42376 var cselitem = false;
42378 var ix = this.view.indexOf(csel[0]);
42379 cselitem = this.store.getAt(ix);
42380 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
42386 this.store.each(function(v) {
42388 // start at existing selection.
42389 if (cselitem.id == v.id) {
42395 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
42396 match = this.store.indexOf(v);
42401 if (match === false) {
42402 return true; // no more action?
42405 this.view.select(match);
42406 var sn = Roo.get(this.view.getSelectedNodes()[0]);
42407 sn.scrollIntoView(sn.dom.parentNode, false);
42411 * @cfg {Boolean} grow
42415 * @cfg {Number} growMin
42419 * @cfg {Number} growMax
42427 * Copyright(c) 2010-2012, Roo J Solutions Limited
42434 * @class Roo.form.ComboBoxArray
42435 * @extends Roo.form.TextField
42436 * A facebook style adder... for lists of email / people / countries etc...
42437 * pick multiple items from a combo box, and shows each one.
42439 * Fred [x] Brian [x] [Pick another |v]
42442 * For this to work: it needs various extra information
42443 * - normal combo problay has
42445 * + displayField, valueField
42447 * For our purpose...
42450 * If we change from 'extends' to wrapping...
42457 * Create a new ComboBoxArray.
42458 * @param {Object} config Configuration options
42462 Roo.form.ComboBoxArray = function(config)
42466 * @event beforeremove
42467 * Fires before remove the value from the list
42468 * @param {Roo.form.ComboBoxArray} _self This combo box array
42469 * @param {Roo.form.ComboBoxArray.Item} item removed item
42471 'beforeremove' : true,
42474 * Fires when remove the value from the list
42475 * @param {Roo.form.ComboBoxArray} _self This combo box array
42476 * @param {Roo.form.ComboBoxArray.Item} item removed item
42483 Roo.form.ComboBoxArray.superclass.constructor.call(this, config);
42485 this.items = new Roo.util.MixedCollection(false);
42487 // construct the child combo...
42497 Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
42500 * @cfg {Roo.form.Combo} combo The combo box that is wrapped
42505 // behavies liek a hiddne field
42506 inputType: 'hidden',
42508 * @cfg {Number} width The width of the box that displays the selected element
42515 * @cfg {String} name The name of the visable items on this form (eg. titles not ids)
42519 * @cfg {String} hiddenName The hidden name of the field, often contains an comma seperated list of names
42521 hiddenName : false,
42523 * @cfg {String} seperator The value seperator normally ','
42527 // private the array of items that are displayed..
42529 // private - the hidden field el.
42531 // private - the filed el..
42534 //validateValue : function() { return true; }, // all values are ok!
42535 //onAddClick: function() { },
42537 onRender : function(ct, position)
42540 // create the standard hidden element
42541 //Roo.form.ComboBoxArray.superclass.onRender.call(this, ct, position);
42544 // give fake names to child combo;
42545 this.combo.hiddenName = this.hiddenName ? (this.hiddenName+'-subcombo') : this.hiddenName;
42546 this.combo.name = this.name ? (this.name+'-subcombo') : this.name;
42548 this.combo = Roo.factory(this.combo, Roo.form);
42549 this.combo.onRender(ct, position);
42550 if (typeof(this.combo.width) != 'undefined') {
42551 this.combo.onResize(this.combo.width,0);
42554 this.combo.initEvents();
42556 // assigned so form know we need to do this..
42557 this.store = this.combo.store;
42558 this.valueField = this.combo.valueField;
42559 this.displayField = this.combo.displayField ;
42562 this.combo.wrap.addClass('x-cbarray-grp');
42564 var cbwrap = this.combo.wrap.createChild(
42565 {tag: 'div', cls: 'x-cbarray-cb'},
42570 this.hiddenEl = this.combo.wrap.createChild({
42571 tag: 'input', type:'hidden' , name: this.hiddenName, value : ''
42573 this.el = this.combo.wrap.createChild({
42574 tag: 'input', type:'hidden' , name: this.name, value : ''
42576 // this.el.dom.removeAttribute("name");
42579 this.outerWrap = this.combo.wrap;
42580 this.wrap = cbwrap;
42582 this.outerWrap.setWidth(this.width);
42583 this.outerWrap.dom.removeChild(this.el.dom);
42585 this.wrap.dom.appendChild(this.el.dom);
42586 this.outerWrap.dom.removeChild(this.combo.trigger.dom);
42587 this.combo.wrap.dom.appendChild(this.combo.trigger.dom);
42589 this.combo.trigger.setStyle('position','relative');
42590 this.combo.trigger.setStyle('left', '0px');
42591 this.combo.trigger.setStyle('top', '2px');
42593 this.combo.el.setStyle('vertical-align', 'text-bottom');
42595 //this.trigger.setStyle('vertical-align', 'top');
42597 // this should use the code from combo really... on('add' ....)
42601 this.adder = this.outerWrap.createChild(
42602 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-adder', style: 'margin-left:2px'});
42604 this.adder.on('click', function(e) {
42605 _t.fireEvent('adderclick', this, e);
42609 //this.adder.on('click', this.onAddClick, _t);
42612 this.combo.on('select', function(cb, rec, ix) {
42613 this.addItem(rec.data);
42616 cb.el.dom.value = '';
42617 //cb.lastData = rec.data;
42626 getName: function()
42628 // returns hidden if it's set..
42629 if (!this.rendered) {return ''};
42630 return this.hiddenName ? this.hiddenName : this.name;
42635 onResize: function(w, h){
42638 // not sure if this is needed..
42639 //this.combo.onResize(w,h);
42641 if(typeof w != 'number'){
42642 // we do not handle it!?!?
42645 var tw = this.combo.trigger.getWidth();
42646 tw += this.addicon ? this.addicon.getWidth() : 0;
42647 tw += this.editicon ? this.editicon.getWidth() : 0;
42649 this.combo.el.setWidth( this.combo.adjustWidth('input', x));
42651 this.combo.trigger.setStyle('left', '0px');
42653 if(this.list && this.listWidth === undefined){
42654 var lw = Math.max(x + this.combo.trigger.getWidth(), this.combo.minListWidth);
42655 this.list.setWidth(lw);
42656 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
42663 addItem: function(rec)
42665 var valueField = this.combo.valueField;
42666 var displayField = this.combo.displayField;
42668 if (this.items.indexOfKey(rec[valueField]) > -1) {
42669 //console.log("GOT " + rec.data.id);
42673 var x = new Roo.form.ComboBoxArray.Item({
42674 //id : rec[this.idField],
42676 displayField : displayField ,
42677 tipField : displayField ,
42681 this.items.add(rec[valueField],x);
42682 // add it before the element..
42683 this.updateHiddenEl();
42684 x.render(this.outerWrap, this.wrap.dom);
42685 // add the image handler..
42688 updateHiddenEl : function()
42691 if (!this.hiddenEl) {
42695 var idField = this.combo.valueField;
42697 this.items.each(function(f) {
42698 ar.push(f.data[idField]);
42700 this.hiddenEl.dom.value = ar.join(this.seperator);
42706 this.items.clear();
42708 Roo.each(this.outerWrap.select('.x-cbarray-item', true).elements, function(el){
42712 this.el.dom.value = '';
42713 if (this.hiddenEl) {
42714 this.hiddenEl.dom.value = '';
42718 getValue: function()
42720 return this.hiddenEl ? this.hiddenEl.dom.value : '';
42722 setValue: function(v) // not a valid action - must use addItems..
42727 if (this.store.isLocal && (typeof(v) == 'string')) {
42728 // then we can use the store to find the values..
42729 // comma seperated at present.. this needs to allow JSON based encoding..
42730 this.hiddenEl.value = v;
42732 Roo.each(v.split(this.seperator), function(k) {
42733 Roo.log("CHECK " + this.valueField + ',' + k);
42734 var li = this.store.query(this.valueField, k);
42739 add[this.valueField] = k;
42740 add[this.displayField] = li.item(0).data[this.displayField];
42746 if (typeof(v) == 'object' ) {
42747 // then let's assume it's an array of objects..
42748 Roo.each(v, function(l) {
42750 if (typeof(l) == 'string') {
42752 add[this.valueField] = l;
42753 add[this.displayField] = l
42762 setFromData: function(v)
42764 // this recieves an object, if setValues is called.
42766 this.el.dom.value = v[this.displayField];
42767 this.hiddenEl.dom.value = v[this.valueField];
42768 if (typeof(v[this.valueField]) != 'string' || !v[this.valueField].length) {
42771 var kv = v[this.valueField];
42772 var dv = v[this.displayField];
42773 kv = typeof(kv) != 'string' ? '' : kv;
42774 dv = typeof(dv) != 'string' ? '' : dv;
42777 var keys = kv.split(this.seperator);
42778 var display = dv.split(this.seperator);
42779 for (var i = 0 ; i < keys.length; i++) {
42781 add[this.valueField] = keys[i];
42782 add[this.displayField] = display[i];
42790 * Validates the combox array value
42791 * @return {Boolean} True if the value is valid, else false
42793 validate : function(){
42794 if(this.disabled || this.validateValue(this.processValue(this.getValue()))){
42795 this.clearInvalid();
42801 validateValue : function(value){
42802 return Roo.form.ComboBoxArray.superclass.validateValue.call(this, this.getValue());
42810 isDirty : function() {
42811 if(this.disabled) {
42816 var d = Roo.decode(String(this.originalValue));
42818 return String(this.getValue()) !== String(this.originalValue);
42821 var originalValue = [];
42823 for (var i = 0; i < d.length; i++){
42824 originalValue.push(d[i][this.valueField]);
42827 return String(this.getValue()) !== String(originalValue.join(this.seperator));
42836 * @class Roo.form.ComboBoxArray.Item
42837 * @extends Roo.BoxComponent
42838 * A selected item in the list
42839 * Fred [x] Brian [x] [Pick another |v]
42842 * Create a new item.
42843 * @param {Object} config Configuration options
42846 Roo.form.ComboBoxArray.Item = function(config) {
42847 config.id = Roo.id();
42848 Roo.form.ComboBoxArray.Item.superclass.constructor.call(this, config);
42851 Roo.extend(Roo.form.ComboBoxArray.Item, Roo.BoxComponent, {
42854 displayField : false,
42858 defaultAutoCreate : {
42860 cls: 'x-cbarray-item',
42867 src : Roo.BLANK_IMAGE_URL ,
42875 onRender : function(ct, position)
42877 Roo.form.Field.superclass.onRender.call(this, ct, position);
42880 var cfg = this.getAutoCreate();
42881 this.el = ct.createChild(cfg, position);
42884 this.el.child('img').dom.setAttribute('src', Roo.BLANK_IMAGE_URL);
42886 this.el.child('div').dom.innerHTML = this.cb.renderer ?
42887 this.cb.renderer(this.data) :
42888 String.format('{0}',this.data[this.displayField]);
42891 this.el.child('div').dom.setAttribute('qtip',
42892 String.format('{0}',this.data[this.tipField])
42895 this.el.child('img').on('click', this.remove, this);
42899 remove : function()
42901 if(this.cb.disabled){
42905 if(false !== this.cb.fireEvent('beforeremove', this.cb, this)){
42906 this.cb.items.remove(this);
42907 this.el.child('img').un('click', this.remove, this);
42909 this.cb.updateHiddenEl();
42911 this.cb.fireEvent('remove', this.cb, this);
42916 * RooJS Library 1.1.1
42917 * Copyright(c) 2008-2011 Alan Knowles
42924 * @class Roo.form.ComboNested
42925 * @extends Roo.form.ComboBox
42926 * A combobox for that allows selection of nested items in a list,
42941 * Create a new ComboNested
42942 * @param {Object} config Configuration options
42944 Roo.form.ComboNested = function(config){
42945 Roo.form.ComboCheck.superclass.constructor.call(this, config);
42946 // should verify some data...
42948 // hiddenName = required..
42949 // displayField = required
42950 // valudField == required
42951 var req= [ 'hiddenName', 'displayField', 'valueField' ];
42953 Roo.each(req, function(e) {
42954 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
42955 throw "Roo.form.ComboNested : missing value for: " + e;
42962 Roo.extend(Roo.form.ComboNested, Roo.form.ComboBox, {
42965 * @config {Number} max Number of columns to show
42970 list : null, // the outermost div..
42971 innerLists : null, // the
42975 loadingChildren : false,
42977 onRender : function(ct, position)
42979 Roo.form.ComboBox.superclass.onRender.call(this, ct, position); // skip parent call - got to above..
42981 if(this.hiddenName){
42982 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
42984 this.hiddenField.value =
42985 this.hiddenValue !== undefined ? this.hiddenValue :
42986 this.value !== undefined ? this.value : '';
42988 // prevent input submission
42989 this.el.dom.removeAttribute('name');
42995 this.el.dom.setAttribute('autocomplete', 'off');
42998 var cls = 'x-combo-list';
43000 this.list = new Roo.Layer({
43001 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
43004 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
43005 this.list.setWidth(lw);
43006 this.list.swallowEvent('mousewheel');
43007 this.assetHeight = 0;
43010 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
43011 this.assetHeight += this.header.getHeight();
43013 this.innerLists = [];
43016 for (var i =0 ; i < this.maxColumns; i++) {
43017 this.onRenderList( cls, i);
43020 // always needs footer, as we are going to have an 'OK' button.
43021 this.footer = this.list.createChild({cls:cls+'-ft'});
43022 this.pageTb = new Roo.Toolbar(this.footer);
43027 handler: function()
43033 if ( this.allowBlank && !this.disableClear) {
43035 this.pageTb.add(new Roo.Toolbar.Fill(), {
43036 cls: 'x-btn-icon x-btn-clear',
43038 handler: function()
43041 _this.clearValue();
43042 _this.onSelect(false, -1);
43047 this.assetHeight += this.footer.getHeight();
43051 onRenderList : function ( cls, i)
43054 var lw = Math.floor(
43055 ((this.listWidth * this.maxColumns || Math.max(this.wrap.getWidth(), this.minListWidth)) - this.list.getFrameWidth('lr')) / this.maxColumns
43058 this.list.setWidth(lw); // default to '1'
43060 var il = this.innerLists[i] = this.list.createChild({cls:cls+'-inner'});
43061 //il.on('mouseover', this.onViewOver, this, { list: i });
43062 //il.on('mousemove', this.onViewMove, this, { list: i });
43064 il.setStyle({ 'overflow-x' : 'hidden'});
43067 this.tpl = new Roo.Template({
43068 html : '<div class="'+cls+'-item '+cls+'-item-{cn:this.isEmpty}">{' + this.displayField + '}</div>',
43069 isEmpty: function (value, allValues) {
43071 var dl = typeof(value.data) != 'undefined' ? value.data.length : value.length; ///json is a nested response..
43072 return dl ? 'has-children' : 'no-children'
43077 var store = this.store;
43079 store = new Roo.data.SimpleStore({
43080 //fields : this.store.reader.meta.fields,
43081 reader : this.store.reader,
43085 this.stores[i] = store;
43087 var view = this.views[i] = new Roo.View(
43093 selectedClass: this.selectedClass
43096 view.getEl().setWidth(lw);
43097 view.getEl().setStyle({
43098 position: i < 1 ? 'relative' : 'absolute',
43100 left: (i * lw ) + 'px',
43101 display : i > 0 ? 'none' : 'block'
43103 view.on('selectionchange', this.onSelectChange.createDelegate(this, {list : i }, true));
43104 view.on('dblclick', this.onDoubleClick.createDelegate(this, {list : i }, true));
43105 //view.on('click', this.onViewClick, this, { list : i });
43107 store.on('beforeload', this.onBeforeLoad, this);
43108 store.on('load', this.onLoad, this, { list : i});
43109 store.on('loadexception', this.onLoadException, this);
43111 // hide the other vies..
43117 restrictHeight : function()
43120 Roo.each(this.innerLists, function(il,i) {
43121 var el = this.views[i].getEl();
43122 el.dom.style.height = '';
43123 var inner = el.dom;
43124 var h = Math.max(il.clientHeight, il.offsetHeight, il.scrollHeight);
43125 // only adjust heights on other ones..
43126 mh = Math.max(h, mh);
43129 el.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
43130 il.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
43137 this.list.beginUpdate();
43138 this.list.setHeight(mh+this.list.getFrameWidth('tb')+this.assetHeight);
43139 this.list.alignTo(this.el, this.listAlign);
43140 this.list.endUpdate();
43145 // -- store handlers..
43147 onBeforeLoad : function()
43149 if(!this.hasFocus){
43152 this.innerLists[0].update(this.loadingText ?
43153 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
43154 this.restrictHeight();
43155 this.selectedIndex = -1;
43158 onLoad : function(a,b,c,d)
43160 if (!this.loadingChildren) {
43161 // then we are loading the top level. - hide the children
43162 for (var i = 1;i < this.views.length; i++) {
43163 this.views[i].getEl().setStyle({ display : 'none' });
43165 var lw = Math.floor(
43166 ((this.listWidth * this.maxColumns || Math.max(this.wrap.getWidth(), this.minListWidth)) - this.list.getFrameWidth('lr')) / this.maxColumns
43169 this.list.setWidth(lw); // default to '1'
43173 if(!this.hasFocus){
43177 if(this.store.getCount() > 0) {
43179 this.restrictHeight();
43181 this.onEmptyResults();
43184 if (!this.loadingChildren) {
43185 this.selectActive();
43188 this.stores[1].loadData([]);
43189 this.stores[2].loadData([]);
43198 onLoadException : function()
43201 Roo.log(this.store.reader.jsonData);
43202 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
43203 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
43208 // no cleaning of leading spaces on blur here.
43209 cleanLeadingSpace : function(e) { },
43212 onSelectChange : function (view, sels, opts )
43214 var ix = view.getSelectedIndexes();
43216 if (opts.list > this.maxColumns - 2) {
43217 if (view.store.getCount()< 1) {
43218 this.views[opts.list ].getEl().setStyle({ display : 'none' });
43222 // used to clear ?? but if we are loading unselected
43223 this.setFromData(view.store.getAt(ix[0]).data);
43232 // this get's fired when trigger opens..
43233 // this.setFromData({});
43234 var str = this.stores[opts.list+1];
43235 str.data.clear(); // removeall wihtout the fire events..
43239 var rec = view.store.getAt(ix[0]);
43241 this.setFromData(rec.data);
43242 this.fireEvent('select', this, rec, ix[0]);
43244 var lw = Math.floor(
43246 (this.listWidth * this.maxColumns || Math.max(this.wrap.getWidth(), this.minListWidth)) - this.list.getFrameWidth('lr')
43247 ) / this.maxColumns
43249 this.loadingChildren = true;
43250 this.stores[opts.list+1].loadDataFromChildren( rec );
43251 this.loadingChildren = false;
43252 var dl = this.stores[opts.list+1]. getTotalCount();
43254 this.views[opts.list+1].getEl().setHeight( this.innerLists[0].getHeight());
43256 this.views[opts.list+1].getEl().setStyle({ display : dl ? 'block' : 'none' });
43257 for (var i = opts.list+2; i < this.views.length;i++) {
43258 this.views[i].getEl().setStyle({ display : 'none' });
43261 this.innerLists[opts.list+1].setHeight( this.innerLists[0].getHeight());
43262 this.list.setWidth(lw * (opts.list + (dl ? 2 : 1)));
43264 if (this.isLoading) {
43265 // this.selectActive(opts.list);
43273 onDoubleClick : function()
43275 this.collapse(); //??
43283 recordToStack : function(store, prop, value, stack)
43285 var cstore = new Roo.data.SimpleStore({
43286 //fields : this.store.reader.meta.fields, // we need array reader.. for
43287 reader : this.store.reader,
43291 var record = false;
43293 if(store.getCount() < 1){
43296 store.each(function(r){
43297 if(r.data[prop] == value){
43302 if (r.data.cn && r.data.cn.length) {
43303 cstore.loadDataFromChildren( r);
43304 var cret = _this.recordToStack(cstore, prop, value, stack);
43305 if (cret !== false) {
43314 if (record == false) {
43317 stack.unshift(srec);
43322 * find the stack of stores that match our value.
43327 selectActive : function ()
43329 // if store is not loaded, then we will need to wait for that to happen first.
43331 this.recordToStack(this.store, this.valueField, this.getValue(), stack);
43332 for (var i = 0; i < stack.length; i++ ) {
43333 this.views[i].select(stack[i].store.indexOf(stack[i]), false, false );
43345 * Ext JS Library 1.1.1
43346 * Copyright(c) 2006-2007, Ext JS, LLC.
43348 * Originally Released Under LGPL - original licence link has changed is not relivant.
43351 * <script type="text/javascript">
43354 * @class Roo.form.Checkbox
43355 * @extends Roo.form.Field
43356 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
43358 * Creates a new Checkbox
43359 * @param {Object} config Configuration options
43361 Roo.form.Checkbox = function(config){
43362 Roo.form.Checkbox.superclass.constructor.call(this, config);
43366 * Fires when the checkbox is checked or unchecked.
43367 * @param {Roo.form.Checkbox} this This checkbox
43368 * @param {Boolean} checked The new checked value
43374 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
43376 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
43378 focusClass : undefined,
43380 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
43382 fieldClass: "x-form-field",
43384 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
43388 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
43389 * {tag: "input", type: "checkbox", autocomplete: "off"})
43391 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
43393 * @cfg {String} boxLabel The text that appears beside the checkbox
43397 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
43401 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
43403 valueOff: '0', // value when not checked..
43405 actionMode : 'viewEl',
43408 itemCls : 'x-menu-check-item x-form-item',
43409 groupClass : 'x-menu-group-item',
43410 inputType : 'hidden',
43413 inSetChecked: false, // check that we are not calling self...
43415 inputElement: false, // real input element?
43416 basedOn: false, // ????
43418 isFormField: true, // not sure where this is needed!!!!
43420 onResize : function(){
43421 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
43422 if(!this.boxLabel){
43423 this.el.alignTo(this.wrap, 'c-c');
43427 initEvents : function(){
43428 Roo.form.Checkbox.superclass.initEvents.call(this);
43429 this.el.on("click", this.onClick, this);
43430 this.el.on("change", this.onClick, this);
43434 getResizeEl : function(){
43438 getPositionEl : function(){
43443 onRender : function(ct, position){
43444 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
43446 if(this.inputValue !== undefined){
43447 this.el.dom.value = this.inputValue;
43450 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
43451 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
43452 var viewEl = this.wrap.createChild({
43453 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
43454 this.viewEl = viewEl;
43455 this.wrap.on('click', this.onClick, this);
43457 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
43458 this.el.on('propertychange', this.setFromHidden, this); //ie
43463 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
43464 // viewEl.on('click', this.onClick, this);
43466 //if(this.checked){
43467 this.setChecked(this.checked);
43469 //this.checked = this.el.dom;
43475 initValue : Roo.emptyFn,
43478 * Returns the checked state of the checkbox.
43479 * @return {Boolean} True if checked, else false
43481 getValue : function(){
43483 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
43485 return this.valueOff;
43490 onClick : function(){
43491 if (this.disabled) {
43494 this.setChecked(!this.checked);
43496 //if(this.el.dom.checked != this.checked){
43497 // this.setValue(this.el.dom.checked);
43502 * Sets the checked state of the checkbox.
43503 * On is always based on a string comparison between inputValue and the param.
43504 * @param {Boolean/String} value - the value to set
43505 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
43507 setValue : function(v,suppressEvent){
43510 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
43511 //if(this.el && this.el.dom){
43512 // this.el.dom.checked = this.checked;
43513 // this.el.dom.defaultChecked = this.checked;
43515 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
43516 //this.fireEvent("check", this, this.checked);
43519 setChecked : function(state,suppressEvent)
43521 if (this.inSetChecked) {
43522 this.checked = state;
43528 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
43530 this.checked = state;
43531 if(suppressEvent !== true){
43532 this.fireEvent('check', this, state);
43534 this.inSetChecked = true;
43535 this.el.dom.value = state ? this.inputValue : this.valueOff;
43536 this.inSetChecked = false;
43539 // handle setting of hidden value by some other method!!?!?
43540 setFromHidden: function()
43545 //console.log("SET FROM HIDDEN");
43546 //alert('setFrom hidden');
43547 this.setValue(this.el.dom.value);
43550 onDestroy : function()
43553 Roo.get(this.viewEl).remove();
43556 Roo.form.Checkbox.superclass.onDestroy.call(this);
43559 setBoxLabel : function(str)
43561 this.wrap.select('.x-form-cb-label', true).first().dom.innerHTML = str;
43566 * Ext JS Library 1.1.1
43567 * Copyright(c) 2006-2007, Ext JS, LLC.
43569 * Originally Released Under LGPL - original licence link has changed is not relivant.
43572 * <script type="text/javascript">
43576 * @class Roo.form.Radio
43577 * @extends Roo.form.Checkbox
43578 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
43579 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
43581 * Creates a new Radio
43582 * @param {Object} config Configuration options
43584 Roo.form.Radio = function(){
43585 Roo.form.Radio.superclass.constructor.apply(this, arguments);
43587 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
43588 inputType: 'radio',
43591 * If this radio is part of a group, it will return the selected value
43594 getGroupValue : function(){
43595 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
43599 onRender : function(ct, position){
43600 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
43602 if(this.inputValue !== undefined){
43603 this.el.dom.value = this.inputValue;
43606 this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
43607 //this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
43608 //var viewEl = this.wrap.createChild({
43609 // tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
43610 //this.viewEl = viewEl;
43611 //this.wrap.on('click', this.onClick, this);
43613 //this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
43614 //this.el.on('propertychange', this.setFromHidden, this); //ie
43619 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
43620 // viewEl.on('click', this.onClick, this);
43623 this.el.dom.checked = 'checked' ;
43629 });//<script type="text/javascript">
43632 * Based Ext JS Library 1.1.1
43633 * Copyright(c) 2006-2007, Ext JS, LLC.
43639 * @class Roo.HtmlEditorCore
43640 * @extends Roo.Component
43641 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
43643 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
43646 Roo.HtmlEditorCore = function(config){
43649 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
43654 * @event initialize
43655 * Fires when the editor is fully initialized (including the iframe)
43656 * @param {Roo.HtmlEditorCore} this
43661 * Fires when the editor is first receives the focus. Any insertion must wait
43662 * until after this event.
43663 * @param {Roo.HtmlEditorCore} this
43667 * @event beforesync
43668 * Fires before the textarea is updated with content from the editor iframe. Return false
43669 * to cancel the sync.
43670 * @param {Roo.HtmlEditorCore} this
43671 * @param {String} html
43675 * @event beforepush
43676 * Fires before the iframe editor is updated with content from the textarea. Return false
43677 * to cancel the push.
43678 * @param {Roo.HtmlEditorCore} this
43679 * @param {String} html
43684 * Fires when the textarea is updated with content from the editor iframe.
43685 * @param {Roo.HtmlEditorCore} this
43686 * @param {String} html
43691 * Fires when the iframe editor is updated with content from the textarea.
43692 * @param {Roo.HtmlEditorCore} this
43693 * @param {String} html
43698 * @event editorevent
43699 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
43700 * @param {Roo.HtmlEditorCore} this
43706 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
43708 // defaults : white / black...
43709 this.applyBlacklists();
43716 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
43720 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
43726 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
43731 * @cfg {Number} height (in pixels)
43735 * @cfg {Number} width (in pixels)
43740 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
43743 stylesheets: false,
43748 // private properties
43749 validationEvent : false,
43751 initialized : false,
43753 sourceEditMode : false,
43754 onFocus : Roo.emptyFn,
43756 hideMode:'offsets',
43760 // blacklist + whitelisted elements..
43767 * Protected method that will not generally be called directly. It
43768 * is called when the editor initializes the iframe with HTML contents. Override this method if you
43769 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
43771 getDocMarkup : function(){
43775 // inherit styels from page...??
43776 if (this.stylesheets === false) {
43778 Roo.get(document.head).select('style').each(function(node) {
43779 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
43782 Roo.get(document.head).select('link').each(function(node) {
43783 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
43786 } else if (!this.stylesheets.length) {
43788 st = '<style type="text/css">' +
43789 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
43792 for (var i in this.stylesheets) {
43793 st += '<link rel="stylesheet" href="' + this.stylesheets[i] +'" type="text/css">';
43798 st += '<style type="text/css">' +
43799 'IMG { cursor: pointer } ' +
43802 var cls = 'roo-htmleditor-body';
43804 if(this.bodyCls.length){
43805 cls += ' ' + this.bodyCls;
43808 return '<html><head>' + st +
43809 //<style type="text/css">' +
43810 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
43812 ' </head><body contenteditable="true" data-enable-grammerly="true" class="' + cls + '"></body></html>';
43816 onRender : function(ct, position)
43819 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
43820 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
43823 this.el.dom.style.border = '0 none';
43824 this.el.dom.setAttribute('tabIndex', -1);
43825 this.el.addClass('x-hidden hide');
43829 if(Roo.isIE){ // fix IE 1px bogus margin
43830 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
43834 this.frameId = Roo.id();
43838 var iframe = this.owner.wrap.createChild({
43840 cls: 'form-control', // bootstrap..
43842 name: this.frameId,
43843 frameBorder : 'no',
43844 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
43849 this.iframe = iframe.dom;
43851 this.assignDocWin();
43853 this.doc.designMode = 'on';
43856 this.doc.write(this.getDocMarkup());
43860 var task = { // must defer to wait for browser to be ready
43862 //console.log("run task?" + this.doc.readyState);
43863 this.assignDocWin();
43864 if(this.doc.body || this.doc.readyState == 'complete'){
43866 this.doc.designMode="on";
43870 Roo.TaskMgr.stop(task);
43871 this.initEditor.defer(10, this);
43878 Roo.TaskMgr.start(task);
43883 onResize : function(w, h)
43885 Roo.log('resize: ' +w + ',' + h );
43886 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
43890 if(typeof w == 'number'){
43892 this.iframe.style.width = w + 'px';
43894 if(typeof h == 'number'){
43896 this.iframe.style.height = h + 'px';
43898 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
43905 * Toggles the editor between standard and source edit mode.
43906 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
43908 toggleSourceEdit : function(sourceEditMode){
43910 this.sourceEditMode = sourceEditMode === true;
43912 if(this.sourceEditMode){
43914 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
43917 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
43918 //this.iframe.className = '';
43921 //this.setSize(this.owner.wrap.getSize());
43922 //this.fireEvent('editmodechange', this, this.sourceEditMode);
43929 * Protected method that will not generally be called directly. If you need/want
43930 * custom HTML cleanup, this is the method you should override.
43931 * @param {String} html The HTML to be cleaned
43932 * return {String} The cleaned HTML
43934 cleanHtml : function(html){
43935 html = String(html);
43936 if(html.length > 5){
43937 if(Roo.isSafari){ // strip safari nonsense
43938 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
43941 if(html == ' '){
43948 * HTML Editor -> Textarea
43949 * Protected method that will not generally be called directly. Syncs the contents
43950 * of the editor iframe with the textarea.
43952 syncValue : function(){
43953 if(this.initialized){
43954 var bd = (this.doc.body || this.doc.documentElement);
43955 //this.cleanUpPaste(); -- this is done else where and causes havoc..
43956 var html = bd.innerHTML;
43958 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
43959 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
43961 html = '<div style="'+m[0]+'">' + html + '</div>';
43964 html = this.cleanHtml(html);
43965 // fix up the special chars.. normaly like back quotes in word...
43966 // however we do not want to do this with chinese..
43967 html = html.replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]|[\u0080-\uFFFF]/g, function(match) {
43969 var cc = match.charCodeAt();
43971 // Get the character value, handling surrogate pairs
43972 if (match.length == 2) {
43973 // It's a surrogate pair, calculate the Unicode code point
43974 var high = match.charCodeAt(0) - 0xD800;
43975 var low = match.charCodeAt(1) - 0xDC00;
43976 cc = (high * 0x400) + low + 0x10000;
43978 (cc >= 0x4E00 && cc < 0xA000 ) ||
43979 (cc >= 0x3400 && cc < 0x4E00 ) ||
43980 (cc >= 0xf900 && cc < 0xfb00 )
43985 // No, use a numeric entity. Here we brazenly (and possibly mistakenly)
43986 return "&#" + cc + ";";
43993 if(this.owner.fireEvent('beforesync', this, html) !== false){
43994 this.el.dom.value = html;
43995 this.owner.fireEvent('sync', this, html);
44001 * Protected method that will not generally be called directly. Pushes the value of the textarea
44002 * into the iframe editor.
44004 pushValue : function(){
44005 if(this.initialized){
44006 var v = this.el.dom.value.trim();
44008 // if(v.length < 1){
44012 if(this.owner.fireEvent('beforepush', this, v) !== false){
44013 var d = (this.doc.body || this.doc.documentElement);
44015 this.cleanUpPaste();
44016 this.el.dom.value = d.innerHTML;
44017 this.owner.fireEvent('push', this, v);
44023 deferFocus : function(){
44024 this.focus.defer(10, this);
44028 focus : function(){
44029 if(this.win && !this.sourceEditMode){
44036 assignDocWin: function()
44038 var iframe = this.iframe;
44041 this.doc = iframe.contentWindow.document;
44042 this.win = iframe.contentWindow;
44044 // if (!Roo.get(this.frameId)) {
44047 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
44048 // this.win = Roo.get(this.frameId).dom.contentWindow;
44050 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
44054 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
44055 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
44060 initEditor : function(){
44061 //console.log("INIT EDITOR");
44062 this.assignDocWin();
44066 this.doc.designMode="on";
44068 this.doc.write(this.getDocMarkup());
44071 var dbody = (this.doc.body || this.doc.documentElement);
44072 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
44073 // this copies styles from the containing element into thsi one..
44074 // not sure why we need all of this..
44075 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
44077 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
44078 //ss['background-attachment'] = 'fixed'; // w3c
44079 dbody.bgProperties = 'fixed'; // ie
44080 //Roo.DomHelper.applyStyles(dbody, ss);
44081 Roo.EventManager.on(this.doc, {
44082 //'mousedown': this.onEditorEvent,
44083 'mouseup': this.onEditorEvent,
44084 'dblclick': this.onEditorEvent,
44085 'click': this.onEditorEvent,
44086 'keyup': this.onEditorEvent,
44091 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
44093 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
44094 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
44096 this.initialized = true;
44098 this.owner.fireEvent('initialize', this);
44103 onDestroy : function(){
44109 //for (var i =0; i < this.toolbars.length;i++) {
44110 // // fixme - ask toolbars for heights?
44111 // this.toolbars[i].onDestroy();
44114 //this.wrap.dom.innerHTML = '';
44115 //this.wrap.remove();
44120 onFirstFocus : function(){
44122 this.assignDocWin();
44125 this.activated = true;
44128 if(Roo.isGecko){ // prevent silly gecko errors
44130 var s = this.win.getSelection();
44131 if(!s.focusNode || s.focusNode.nodeType != 3){
44132 var r = s.getRangeAt(0);
44133 r.selectNodeContents((this.doc.body || this.doc.documentElement));
44138 this.execCmd('useCSS', true);
44139 this.execCmd('styleWithCSS', false);
44142 this.owner.fireEvent('activate', this);
44146 adjustFont: function(btn){
44147 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
44148 //if(Roo.isSafari){ // safari
44151 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
44152 if(Roo.isSafari){ // safari
44153 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
44154 v = (v < 10) ? 10 : v;
44155 v = (v > 48) ? 48 : v;
44156 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
44161 v = Math.max(1, v+adjust);
44163 this.execCmd('FontSize', v );
44166 onEditorEvent : function(e)
44168 this.owner.fireEvent('editorevent', this, e);
44169 // this.updateToolbar();
44170 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
44173 insertTag : function(tg)
44175 // could be a bit smarter... -> wrap the current selected tRoo..
44176 if (tg.toLowerCase() == 'span' ||
44177 tg.toLowerCase() == 'code' ||
44178 tg.toLowerCase() == 'sup' ||
44179 tg.toLowerCase() == 'sub'
44182 range = this.createRange(this.getSelection());
44183 var wrappingNode = this.doc.createElement(tg.toLowerCase());
44184 wrappingNode.appendChild(range.extractContents());
44185 range.insertNode(wrappingNode);
44192 this.execCmd("formatblock", tg);
44196 insertText : function(txt)
44200 var range = this.createRange();
44201 range.deleteContents();
44202 //alert(Sender.getAttribute('label'));
44204 range.insertNode(this.doc.createTextNode(txt));
44210 * Executes a Midas editor command on the editor document and performs necessary focus and
44211 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
44212 * @param {String} cmd The Midas command
44213 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
44215 relayCmd : function(cmd, value){
44217 this.execCmd(cmd, value);
44218 this.owner.fireEvent('editorevent', this);
44219 //this.updateToolbar();
44220 this.owner.deferFocus();
44224 * Executes a Midas editor command directly on the editor document.
44225 * For visual commands, you should use {@link #relayCmd} instead.
44226 * <b>This should only be called after the editor is initialized.</b>
44227 * @param {String} cmd The Midas command
44228 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
44230 execCmd : function(cmd, value){
44231 this.doc.execCommand(cmd, false, value === undefined ? null : value);
44238 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
44240 * @param {String} text | dom node..
44242 insertAtCursor : function(text)
44245 if(!this.activated){
44251 var r = this.doc.selection.createRange();
44262 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
44266 // from jquery ui (MIT licenced)
44268 var win = this.win;
44270 if (win.getSelection && win.getSelection().getRangeAt) {
44271 range = win.getSelection().getRangeAt(0);
44272 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
44273 range.insertNode(node);
44274 } else if (win.document.selection && win.document.selection.createRange) {
44275 // no firefox support
44276 var txt = typeof(text) == 'string' ? text : text.outerHTML;
44277 win.document.selection.createRange().pasteHTML(txt);
44279 // no firefox support
44280 var txt = typeof(text) == 'string' ? text : text.outerHTML;
44281 this.execCmd('InsertHTML', txt);
44290 mozKeyPress : function(e){
44292 var c = e.getCharCode(), cmd;
44295 c = String.fromCharCode(c).toLowerCase();
44309 this.cleanUpPaste.defer(100, this);
44317 e.preventDefault();
44325 fixKeys : function(){ // load time branching for fastest keydown performance
44327 return function(e){
44328 var k = e.getKey(), r;
44331 r = this.doc.selection.createRange();
44334 r.pasteHTML('    ');
44341 r = this.doc.selection.createRange();
44343 var target = r.parentElement();
44344 if(!target || target.tagName.toLowerCase() != 'li'){
44346 r.pasteHTML('<br />');
44352 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
44353 this.cleanUpPaste.defer(100, this);
44359 }else if(Roo.isOpera){
44360 return function(e){
44361 var k = e.getKey();
44365 this.execCmd('InsertHTML','    ');
44368 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
44369 this.cleanUpPaste.defer(100, this);
44374 }else if(Roo.isSafari){
44375 return function(e){
44376 var k = e.getKey();
44380 this.execCmd('InsertText','\t');
44384 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
44385 this.cleanUpPaste.defer(100, this);
44393 getAllAncestors: function()
44395 var p = this.getSelectedNode();
44398 a.push(p); // push blank onto stack..
44399 p = this.getParentElement();
44403 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
44407 a.push(this.doc.body);
44411 lastSelNode : false,
44414 getSelection : function()
44416 this.assignDocWin();
44417 return Roo.isIE ? this.doc.selection : this.win.getSelection();
44420 getSelectedNode: function()
44422 // this may only work on Gecko!!!
44424 // should we cache this!!!!
44429 var range = this.createRange(this.getSelection()).cloneRange();
44432 var parent = range.parentElement();
44434 var testRange = range.duplicate();
44435 testRange.moveToElementText(parent);
44436 if (testRange.inRange(range)) {
44439 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
44442 parent = parent.parentElement;
44447 // is ancestor a text element.
44448 var ac = range.commonAncestorContainer;
44449 if (ac.nodeType == 3) {
44450 ac = ac.parentNode;
44453 var ar = ac.childNodes;
44456 var other_nodes = [];
44457 var has_other_nodes = false;
44458 for (var i=0;i<ar.length;i++) {
44459 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
44462 // fullly contained node.
44464 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
44469 // probably selected..
44470 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
44471 other_nodes.push(ar[i]);
44475 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
44480 has_other_nodes = true;
44482 if (!nodes.length && other_nodes.length) {
44483 nodes= other_nodes;
44485 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
44491 createRange: function(sel)
44493 // this has strange effects when using with
44494 // top toolbar - not sure if it's a great idea.
44495 //this.editor.contentWindow.focus();
44496 if (typeof sel != "undefined") {
44498 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
44500 return this.doc.createRange();
44503 return this.doc.createRange();
44506 getParentElement: function()
44509 this.assignDocWin();
44510 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
44512 var range = this.createRange(sel);
44515 var p = range.commonAncestorContainer;
44516 while (p.nodeType == 3) { // text node
44527 * Range intersection.. the hard stuff...
44531 * [ -- selected range --- ]
44535 * if end is before start or hits it. fail.
44536 * if start is after end or hits it fail.
44538 * if either hits (but other is outside. - then it's not
44544 // @see http://www.thismuchiknow.co.uk/?p=64.
44545 rangeIntersectsNode : function(range, node)
44547 var nodeRange = node.ownerDocument.createRange();
44549 nodeRange.selectNode(node);
44551 nodeRange.selectNodeContents(node);
44554 var rangeStartRange = range.cloneRange();
44555 rangeStartRange.collapse(true);
44557 var rangeEndRange = range.cloneRange();
44558 rangeEndRange.collapse(false);
44560 var nodeStartRange = nodeRange.cloneRange();
44561 nodeStartRange.collapse(true);
44563 var nodeEndRange = nodeRange.cloneRange();
44564 nodeEndRange.collapse(false);
44566 return rangeStartRange.compareBoundaryPoints(
44567 Range.START_TO_START, nodeEndRange) == -1 &&
44568 rangeEndRange.compareBoundaryPoints(
44569 Range.START_TO_START, nodeStartRange) == 1;
44573 rangeCompareNode : function(range, node)
44575 var nodeRange = node.ownerDocument.createRange();
44577 nodeRange.selectNode(node);
44579 nodeRange.selectNodeContents(node);
44583 range.collapse(true);
44585 nodeRange.collapse(true);
44587 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
44588 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
44590 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
44592 var nodeIsBefore = ss == 1;
44593 var nodeIsAfter = ee == -1;
44595 if (nodeIsBefore && nodeIsAfter) {
44598 if (!nodeIsBefore && nodeIsAfter) {
44599 return 1; //right trailed.
44602 if (nodeIsBefore && !nodeIsAfter) {
44603 return 2; // left trailed.
44609 // private? - in a new class?
44610 cleanUpPaste : function()
44612 // cleans up the whole document..
44613 Roo.log('cleanuppaste');
44615 this.cleanUpChildren(this.doc.body);
44616 var clean = this.cleanWordChars(this.doc.body.innerHTML);
44617 if (clean != this.doc.body.innerHTML) {
44618 this.doc.body.innerHTML = clean;
44623 cleanWordChars : function(input) {// change the chars to hex code
44624 var he = Roo.HtmlEditorCore;
44626 var output = input;
44627 Roo.each(he.swapCodes, function(sw) {
44628 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
44630 output = output.replace(swapper, sw[1]);
44637 cleanUpChildren : function (n)
44639 if (!n.childNodes.length) {
44642 for (var i = n.childNodes.length-1; i > -1 ; i--) {
44643 this.cleanUpChild(n.childNodes[i]);
44650 cleanUpChild : function (node)
44653 //console.log(node);
44654 if (node.nodeName == "#text") {
44655 // clean up silly Windows -- stuff?
44658 if (node.nodeName == "#comment") {
44659 node.parentNode.removeChild(node);
44660 // clean up silly Windows -- stuff?
44663 var lcname = node.tagName.toLowerCase();
44664 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
44665 // whitelist of tags..
44667 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
44669 node.parentNode.removeChild(node);
44674 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
44676 // spans with no attributes - just remove them..
44677 if ((!node.attributes || !node.attributes.length) && lcname == 'span') {
44678 remove_keep_children = true;
44681 // remove <a name=....> as rendering on yahoo mailer is borked with this.
44682 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
44684 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
44685 // remove_keep_children = true;
44688 if (remove_keep_children) {
44689 this.cleanUpChildren(node);
44690 // inserts everything just before this node...
44691 while (node.childNodes.length) {
44692 var cn = node.childNodes[0];
44693 node.removeChild(cn);
44694 node.parentNode.insertBefore(cn, node);
44696 node.parentNode.removeChild(node);
44700 if (!node.attributes || !node.attributes.length) {
44705 this.cleanUpChildren(node);
44709 function cleanAttr(n,v)
44712 if (v.match(/^\./) || v.match(/^\//)) {
44715 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/) || v.match(/^ftp:/)) {
44718 if (v.match(/^#/)) {
44721 if (v.match(/^\{/)) { // allow template editing.
44724 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
44725 node.removeAttribute(n);
44729 var cwhite = this.cwhite;
44730 var cblack = this.cblack;
44732 function cleanStyle(n,v)
44734 if (v.match(/expression/)) { //XSS?? should we even bother..
44735 node.removeAttribute(n);
44739 var parts = v.split(/;/);
44742 Roo.each(parts, function(p) {
44743 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
44747 var l = p.split(':').shift().replace(/\s+/g,'');
44748 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
44750 if ( cwhite.length && cblack.indexOf(l) > -1) {
44751 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
44752 //node.removeAttribute(n);
44756 // only allow 'c whitelisted system attributes'
44757 if ( cwhite.length && cwhite.indexOf(l) < 0) {
44758 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
44759 //node.removeAttribute(n);
44769 if (clean.length) {
44770 node.setAttribute(n, clean.join(';'));
44772 node.removeAttribute(n);
44778 for (var i = node.attributes.length-1; i > -1 ; i--) {
44779 var a = node.attributes[i];
44782 if (a.name.toLowerCase().substr(0,2)=='on') {
44783 node.removeAttribute(a.name);
44786 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
44787 node.removeAttribute(a.name);
44790 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
44791 cleanAttr(a.name,a.value); // fixme..
44794 if (a.name == 'style') {
44795 cleanStyle(a.name,a.value);
44798 /// clean up MS crap..
44799 // tecnically this should be a list of valid class'es..
44802 if (a.name == 'class') {
44803 if (a.value.match(/^Mso/)) {
44804 node.removeAttribute('class');
44807 if (a.value.match(/^body$/)) {
44808 node.removeAttribute('class');
44819 this.cleanUpChildren(node);
44825 * Clean up MS wordisms...
44827 cleanWord : function(node)
44830 this.cleanWord(this.doc.body);
44835 node.nodeName == 'SPAN' &&
44836 !node.hasAttributes() &&
44837 node.childNodes.length == 1 &&
44838 node.firstChild.nodeName == "#text"
44840 var textNode = node.firstChild;
44841 node.removeChild(textNode);
44842 if (node.getAttribute('lang') != 'zh-CN') { // do not space pad on chinese characters..
44843 node.parentNode.insertBefore(node.ownerDocument.createTextNode(" "), node);
44845 node.parentNode.insertBefore(textNode, node);
44846 if (node.getAttribute('lang') != 'zh-CN') { // do not space pad on chinese characters..
44847 node.parentNode.insertBefore(node.ownerDocument.createTextNode(" ") , node);
44849 node.parentNode.removeChild(node);
44852 if (node.nodeName == "#text") {
44853 // clean up silly Windows -- stuff?
44856 if (node.nodeName == "#comment") {
44857 node.parentNode.removeChild(node);
44858 // clean up silly Windows -- stuff?
44862 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
44863 node.parentNode.removeChild(node);
44866 //Roo.log(node.tagName);
44867 // remove - but keep children..
44868 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|v:|font)/)) {
44869 //Roo.log('-- removed');
44870 while (node.childNodes.length) {
44871 var cn = node.childNodes[0];
44872 node.removeChild(cn);
44873 node.parentNode.insertBefore(cn, node);
44874 // move node to parent - and clean it..
44875 this.cleanWord(cn);
44877 node.parentNode.removeChild(node);
44878 /// no need to iterate chidlren = it's got none..
44879 //this.iterateChildren(node, this.cleanWord);
44883 if (node.className.length) {
44885 var cn = node.className.split(/\W+/);
44887 Roo.each(cn, function(cls) {
44888 if (cls.match(/Mso[a-zA-Z]+/)) {
44893 node.className = cna.length ? cna.join(' ') : '';
44895 node.removeAttribute("class");
44899 if (node.hasAttribute("lang")) {
44900 node.removeAttribute("lang");
44903 if (node.hasAttribute("style")) {
44905 var styles = node.getAttribute("style").split(";");
44907 Roo.each(styles, function(s) {
44908 if (!s.match(/:/)) {
44911 var kv = s.split(":");
44912 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
44915 // what ever is left... we allow.
44918 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
44919 if (!nstyle.length) {
44920 node.removeAttribute('style');
44923 this.iterateChildren(node, this.cleanWord);
44929 * iterateChildren of a Node, calling fn each time, using this as the scole..
44930 * @param {DomNode} node node to iterate children of.
44931 * @param {Function} fn method of this class to call on each item.
44933 iterateChildren : function(node, fn)
44935 if (!node.childNodes.length) {
44938 for (var i = node.childNodes.length-1; i > -1 ; i--) {
44939 fn.call(this, node.childNodes[i])
44945 * cleanTableWidths.
44947 * Quite often pasting from word etc.. results in tables with column and widths.
44948 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
44951 cleanTableWidths : function(node)
44956 this.cleanTableWidths(this.doc.body);
44961 if (node.nodeName == "#text" || node.nodeName == "#comment") {
44964 Roo.log(node.tagName);
44965 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
44966 this.iterateChildren(node, this.cleanTableWidths);
44969 if (node.hasAttribute('width')) {
44970 node.removeAttribute('width');
44974 if (node.hasAttribute("style")) {
44977 var styles = node.getAttribute("style").split(";");
44979 Roo.each(styles, function(s) {
44980 if (!s.match(/:/)) {
44983 var kv = s.split(":");
44984 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
44987 // what ever is left... we allow.
44990 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
44991 if (!nstyle.length) {
44992 node.removeAttribute('style');
44996 this.iterateChildren(node, this.cleanTableWidths);
45004 domToHTML : function(currentElement, depth, nopadtext) {
45006 depth = depth || 0;
45007 nopadtext = nopadtext || false;
45009 if (!currentElement) {
45010 return this.domToHTML(this.doc.body);
45013 //Roo.log(currentElement);
45015 var allText = false;
45016 var nodeName = currentElement.nodeName;
45017 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
45019 if (nodeName == '#text') {
45021 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
45026 if (nodeName != 'BODY') {
45029 // Prints the node tagName, such as <A>, <IMG>, etc
45032 for(i = 0; i < currentElement.attributes.length;i++) {
45034 var aname = currentElement.attributes.item(i).name;
45035 if (!currentElement.attributes.item(i).value.length) {
45038 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
45041 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
45050 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
45053 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
45058 // Traverse the tree
45060 var currentElementChild = currentElement.childNodes.item(i);
45061 var allText = true;
45062 var innerHTML = '';
45064 while (currentElementChild) {
45065 // Formatting code (indent the tree so it looks nice on the screen)
45066 var nopad = nopadtext;
45067 if (lastnode == 'SPAN') {
45071 if (currentElementChild.nodeName == '#text') {
45072 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
45073 toadd = nopadtext ? toadd : toadd.trim();
45074 if (!nopad && toadd.length > 80) {
45075 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
45077 innerHTML += toadd;
45080 currentElementChild = currentElement.childNodes.item(i);
45086 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
45088 // Recursively traverse the tree structure of the child node
45089 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
45090 lastnode = currentElementChild.nodeName;
45092 currentElementChild=currentElement.childNodes.item(i);
45098 // The remaining code is mostly for formatting the tree
45099 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
45104 ret+= "</"+tagName+">";
45110 applyBlacklists : function()
45112 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
45113 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
45117 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
45118 if (b.indexOf(tag) > -1) {
45121 this.white.push(tag);
45125 Roo.each(w, function(tag) {
45126 if (b.indexOf(tag) > -1) {
45129 if (this.white.indexOf(tag) > -1) {
45132 this.white.push(tag);
45137 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
45138 if (w.indexOf(tag) > -1) {
45141 this.black.push(tag);
45145 Roo.each(b, function(tag) {
45146 if (w.indexOf(tag) > -1) {
45149 if (this.black.indexOf(tag) > -1) {
45152 this.black.push(tag);
45157 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
45158 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
45162 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
45163 if (b.indexOf(tag) > -1) {
45166 this.cwhite.push(tag);
45170 Roo.each(w, function(tag) {
45171 if (b.indexOf(tag) > -1) {
45174 if (this.cwhite.indexOf(tag) > -1) {
45177 this.cwhite.push(tag);
45182 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
45183 if (w.indexOf(tag) > -1) {
45186 this.cblack.push(tag);
45190 Roo.each(b, function(tag) {
45191 if (w.indexOf(tag) > -1) {
45194 if (this.cblack.indexOf(tag) > -1) {
45197 this.cblack.push(tag);
45202 setStylesheets : function(stylesheets)
45204 if(typeof(stylesheets) == 'string'){
45205 Roo.get(this.iframe.contentDocument.head).createChild({
45207 rel : 'stylesheet',
45216 Roo.each(stylesheets, function(s) {
45221 Roo.get(_this.iframe.contentDocument.head).createChild({
45223 rel : 'stylesheet',
45232 removeStylesheets : function()
45236 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
45241 setStyle : function(style)
45243 Roo.get(this.iframe.contentDocument.head).createChild({
45252 // hide stuff that is not compatible
45266 * @event specialkey
45270 * @cfg {String} fieldClass @hide
45273 * @cfg {String} focusClass @hide
45276 * @cfg {String} autoCreate @hide
45279 * @cfg {String} inputType @hide
45282 * @cfg {String} invalidClass @hide
45285 * @cfg {String} invalidText @hide
45288 * @cfg {String} msgFx @hide
45291 * @cfg {String} validateOnBlur @hide
45295 Roo.HtmlEditorCore.white = [
45296 'area', 'br', 'img', 'input', 'hr', 'wbr',
45298 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
45299 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
45300 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
45301 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
45302 'table', 'ul', 'xmp',
45304 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
45307 'dir', 'menu', 'ol', 'ul', 'dl',
45313 Roo.HtmlEditorCore.black = [
45314 // 'embed', 'object', // enable - backend responsiblity to clean thiese
45316 'base', 'basefont', 'bgsound', 'blink', 'body',
45317 'frame', 'frameset', 'head', 'html', 'ilayer',
45318 'iframe', 'layer', 'link', 'meta', 'object',
45319 'script', 'style' ,'title', 'xml' // clean later..
45321 Roo.HtmlEditorCore.clean = [
45322 'script', 'style', 'title', 'xml'
45324 Roo.HtmlEditorCore.remove = [
45329 Roo.HtmlEditorCore.ablack = [
45333 Roo.HtmlEditorCore.aclean = [
45334 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
45338 Roo.HtmlEditorCore.pwhite= [
45339 'http', 'https', 'mailto'
45342 // white listed style attributes.
45343 Roo.HtmlEditorCore.cwhite= [
45344 // 'text-align', /// default is to allow most things..
45350 // black listed style attributes.
45351 Roo.HtmlEditorCore.cblack= [
45352 // 'font-size' -- this can be set by the project
45356 Roo.HtmlEditorCore.swapCodes =[
45357 [ 8211, "–" ],
45358 [ 8212, "—" ],
45367 //<script type="text/javascript">
45370 * Ext JS Library 1.1.1
45371 * Copyright(c) 2006-2007, Ext JS, LLC.
45377 Roo.form.HtmlEditor = function(config){
45381 Roo.form.HtmlEditor.superclass.constructor.call(this, config);
45383 if (!this.toolbars) {
45384 this.toolbars = [];
45386 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
45392 * @class Roo.form.HtmlEditor
45393 * @extends Roo.form.Field
45394 * Provides a lightweight HTML Editor component.
45396 * This has been tested on Fireforx / Chrome.. IE may not be so great..
45398 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
45399 * supported by this editor.</b><br/><br/>
45400 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
45401 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
45403 Roo.extend(Roo.form.HtmlEditor, Roo.form.Field, {
45405 * @cfg {Boolean} clearUp
45409 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
45414 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
45419 * @cfg {Number} height (in pixels)
45423 * @cfg {Number} width (in pixels)
45428 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
45431 stylesheets: false,
45435 * @cfg {Array} blacklist of css styles style attributes (blacklist overrides whitelist)
45440 * @cfg {Array} whitelist of css styles style attributes (blacklist overrides whitelist)
45446 * @cfg {Array} blacklist of html tags - in addition to standard blacklist.
45451 * @cfg {Array} whitelist of html tags - in addition to statndard whitelist
45459 // private properties
45460 validationEvent : false,
45462 initialized : false,
45465 onFocus : Roo.emptyFn,
45467 hideMode:'offsets',
45469 actionMode : 'container', // defaults to hiding it...
45471 defaultAutoCreate : { // modified by initCompnoent..
45473 style:"width:500px;height:300px;",
45474 autocomplete: "new-password"
45478 initComponent : function(){
45481 * @event initialize
45482 * Fires when the editor is fully initialized (including the iframe)
45483 * @param {HtmlEditor} this
45488 * Fires when the editor is first receives the focus. Any insertion must wait
45489 * until after this event.
45490 * @param {HtmlEditor} this
45494 * @event beforesync
45495 * Fires before the textarea is updated with content from the editor iframe. Return false
45496 * to cancel the sync.
45497 * @param {HtmlEditor} this
45498 * @param {String} html
45502 * @event beforepush
45503 * Fires before the iframe editor is updated with content from the textarea. Return false
45504 * to cancel the push.
45505 * @param {HtmlEditor} this
45506 * @param {String} html
45511 * Fires when the textarea is updated with content from the editor iframe.
45512 * @param {HtmlEditor} this
45513 * @param {String} html
45518 * Fires when the iframe editor is updated with content from the textarea.
45519 * @param {HtmlEditor} this
45520 * @param {String} html
45524 * @event editmodechange
45525 * Fires when the editor switches edit modes
45526 * @param {HtmlEditor} this
45527 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
45529 editmodechange: true,
45531 * @event editorevent
45532 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
45533 * @param {HtmlEditor} this
45537 * @event firstfocus
45538 * Fires when on first focus - needed by toolbars..
45539 * @param {HtmlEditor} this
45544 * Auto save the htmlEditor value as a file into Events
45545 * @param {HtmlEditor} this
45549 * @event savedpreview
45550 * preview the saved version of htmlEditor
45551 * @param {HtmlEditor} this
45553 savedpreview: true,
45556 * @event stylesheetsclick
45557 * Fires when press the Sytlesheets button
45558 * @param {Roo.HtmlEditorCore} this
45560 stylesheetsclick: true
45562 this.defaultAutoCreate = {
45564 style:'width: ' + this.width + 'px;height: ' + this.height + 'px;',
45565 autocomplete: "new-password"
45570 * Protected method that will not generally be called directly. It
45571 * is called when the editor creates its toolbar. Override this method if you need to
45572 * add custom toolbar buttons.
45573 * @param {HtmlEditor} editor
45575 createToolbar : function(editor){
45576 Roo.log("create toolbars");
45577 if (!editor.toolbars || !editor.toolbars.length) {
45578 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
45581 for (var i =0 ; i < editor.toolbars.length;i++) {
45582 editor.toolbars[i] = Roo.factory(
45583 typeof(editor.toolbars[i]) == 'string' ?
45584 { xtype: editor.toolbars[i]} : editor.toolbars[i],
45585 Roo.form.HtmlEditor);
45586 editor.toolbars[i].init(editor);
45594 onRender : function(ct, position)
45597 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
45599 this.wrap = this.el.wrap({
45600 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
45603 this.editorcore.onRender(ct, position);
45605 if (this.resizable) {
45606 this.resizeEl = new Roo.Resizable(this.wrap, {
45610 minHeight : this.height,
45611 height: this.height,
45612 handles : this.resizable,
45615 resize : function(r, w, h) {
45616 _t.onResize(w,h); // -something
45622 this.createToolbar(this);
45626 this.setSize(this.wrap.getSize());
45628 if (this.resizeEl) {
45629 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
45630 // should trigger onReize..
45633 this.keyNav = new Roo.KeyNav(this.el, {
45635 "tab" : function(e){
45636 e.preventDefault();
45638 var value = this.getValue();
45640 var start = this.el.dom.selectionStart;
45641 var end = this.el.dom.selectionEnd;
45645 this.setValue(value.substring(0, start) + "\t" + value.substring(end));
45646 this.el.dom.setSelectionRange(end + 1, end + 1);
45650 var f = value.substring(0, start).split("\t");
45652 if(f.pop().length != 0){
45656 this.setValue(f.join("\t") + value.substring(end));
45657 this.el.dom.setSelectionRange(start - 1, start - 1);
45661 "home" : function(e){
45662 e.preventDefault();
45664 var curr = this.el.dom.selectionStart;
45665 var lines = this.getValue().split("\n");
45672 this.el.dom.setSelectionRange(0, 0);
45678 for (var i = 0; i < lines.length;i++) {
45679 pos += lines[i].length;
45689 pos -= lines[i].length;
45695 this.el.dom.setSelectionRange(pos, pos);
45699 this.el.dom.selectionStart = pos;
45700 this.el.dom.selectionEnd = curr;
45703 "end" : function(e){
45704 e.preventDefault();
45706 var curr = this.el.dom.selectionStart;
45707 var lines = this.getValue().split("\n");
45714 this.el.dom.setSelectionRange(this.getValue().length, this.getValue().length);
45720 for (var i = 0; i < lines.length;i++) {
45722 pos += lines[i].length;
45736 this.el.dom.setSelectionRange(pos, pos);
45740 this.el.dom.selectionStart = curr;
45741 this.el.dom.selectionEnd = pos;
45746 doRelay : function(foo, bar, hname){
45747 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
45753 // if(this.autosave && this.w){
45754 // this.autoSaveFn = setInterval(this.autosave, 1000);
45759 onResize : function(w, h)
45761 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
45766 if(typeof w == 'number'){
45767 var aw = w - this.wrap.getFrameWidth('lr');
45768 this.el.setWidth(this.adjustWidth('textarea', aw));
45771 if(typeof h == 'number'){
45773 for (var i =0; i < this.toolbars.length;i++) {
45774 // fixme - ask toolbars for heights?
45775 tbh += this.toolbars[i].tb.el.getHeight();
45776 if (this.toolbars[i].footer) {
45777 tbh += this.toolbars[i].footer.el.getHeight();
45784 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
45785 ah -= 5; // knock a few pixes off for look..
45787 this.el.setHeight(this.adjustWidth('textarea', ah));
45791 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
45792 this.editorcore.onResize(ew,eh);
45797 * Toggles the editor between standard and source edit mode.
45798 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
45800 toggleSourceEdit : function(sourceEditMode)
45802 this.editorcore.toggleSourceEdit(sourceEditMode);
45804 if(this.editorcore.sourceEditMode){
45805 Roo.log('editor - showing textarea');
45808 // Roo.log(this.syncValue());
45809 this.editorcore.syncValue();
45810 this.el.removeClass('x-hidden');
45811 this.el.dom.removeAttribute('tabIndex');
45814 for (var i = 0; i < this.toolbars.length; i++) {
45815 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
45816 this.toolbars[i].tb.hide();
45817 this.toolbars[i].footer.hide();
45822 Roo.log('editor - hiding textarea');
45824 // Roo.log(this.pushValue());
45825 this.editorcore.pushValue();
45827 this.el.addClass('x-hidden');
45828 this.el.dom.setAttribute('tabIndex', -1);
45830 for (var i = 0; i < this.toolbars.length; i++) {
45831 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
45832 this.toolbars[i].tb.show();
45833 this.toolbars[i].footer.show();
45837 //this.deferFocus();
45840 this.setSize(this.wrap.getSize());
45841 this.onResize(this.wrap.getSize().width, this.wrap.getSize().height);
45843 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
45846 // private (for BoxComponent)
45847 adjustSize : Roo.BoxComponent.prototype.adjustSize,
45849 // private (for BoxComponent)
45850 getResizeEl : function(){
45854 // private (for BoxComponent)
45855 getPositionEl : function(){
45860 initEvents : function(){
45861 this.originalValue = this.getValue();
45865 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
45868 markInvalid : Roo.emptyFn,
45870 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
45873 clearInvalid : Roo.emptyFn,
45875 setValue : function(v){
45876 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
45877 this.editorcore.pushValue();
45882 deferFocus : function(){
45883 this.focus.defer(10, this);
45887 focus : function(){
45888 this.editorcore.focus();
45894 onDestroy : function(){
45900 for (var i =0; i < this.toolbars.length;i++) {
45901 // fixme - ask toolbars for heights?
45902 this.toolbars[i].onDestroy();
45905 this.wrap.dom.innerHTML = '';
45906 this.wrap.remove();
45911 onFirstFocus : function(){
45912 //Roo.log("onFirstFocus");
45913 this.editorcore.onFirstFocus();
45914 for (var i =0; i < this.toolbars.length;i++) {
45915 this.toolbars[i].onFirstFocus();
45921 syncValue : function()
45923 this.editorcore.syncValue();
45926 pushValue : function()
45928 this.editorcore.pushValue();
45931 setStylesheets : function(stylesheets)
45933 this.editorcore.setStylesheets(stylesheets);
45936 removeStylesheets : function()
45938 this.editorcore.removeStylesheets();
45942 // hide stuff that is not compatible
45956 * @event specialkey
45960 * @cfg {String} fieldClass @hide
45963 * @cfg {String} focusClass @hide
45966 * @cfg {String} autoCreate @hide
45969 * @cfg {String} inputType @hide
45972 * @cfg {String} invalidClass @hide
45975 * @cfg {String} invalidText @hide
45978 * @cfg {String} msgFx @hide
45981 * @cfg {String} validateOnBlur @hide
45985 // <script type="text/javascript">
45988 * Ext JS Library 1.1.1
45989 * Copyright(c) 2006-2007, Ext JS, LLC.
45995 * @class Roo.form.HtmlEditorToolbar1
46000 new Roo.form.HtmlEditor({
46003 new Roo.form.HtmlEditorToolbar1({
46004 disable : { fonts: 1 , format: 1, ..., ... , ...],
46010 * @cfg {Object} disable List of elements to disable..
46011 * @cfg {Array} btns List of additional buttons.
46015 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
46018 Roo.form.HtmlEditor.ToolbarStandard = function(config)
46021 Roo.apply(this, config);
46023 // default disabled, based on 'good practice'..
46024 this.disable = this.disable || {};
46025 Roo.applyIf(this.disable, {
46028 specialElements : true
46032 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
46033 // dont call parent... till later.
46036 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
46043 editorcore : false,
46045 * @cfg {Object} disable List of toolbar elements to disable
46052 * @cfg {String} createLinkText The default text for the create link prompt
46054 createLinkText : 'Please enter the URL for the link:',
46056 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
46058 defaultLinkValue : 'http:/'+'/',
46062 * @cfg {Array} fontFamilies An array of available font families
46080 // "á" , ?? a acute?
46085 "°" // , // degrees
46087 // "é" , // e ecute
46088 // "ú" , // u ecute?
46091 specialElements : [
46093 text: "Insert Table",
46096 ihtml : '<table><tr><td>Cell</td></tr></table>'
46100 text: "Insert Image",
46103 ihtml : '<img src="about:blank"/>'
46112 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
46113 "input:submit", "input:button", "select", "textarea", "label" ],
46116 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
46118 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"],
46127 * @cfg {String} defaultFont default font to use.
46129 defaultFont: 'tahoma',
46131 fontSelect : false,
46134 formatCombo : false,
46136 init : function(editor)
46138 this.editor = editor;
46139 this.editorcore = editor.editorcore ? editor.editorcore : editor;
46140 var editorcore = this.editorcore;
46144 var fid = editorcore.frameId;
46146 function btn(id, toggle, handler){
46147 var xid = fid + '-'+ id ;
46151 cls : 'x-btn-icon x-edit-'+id,
46152 enableToggle:toggle !== false,
46153 scope: _t, // was editor...
46154 handler:handler||_t.relayBtnCmd,
46155 clickEvent:'mousedown',
46156 tooltip: etb.buttonTips[id] || undefined, ///tips ???
46163 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
46165 // stop form submits
46166 tb.el.on('click', function(e){
46167 e.preventDefault(); // what does this do?
46170 if(!this.disable.font) { // && !Roo.isSafari){
46171 /* why no safari for fonts
46172 editor.fontSelect = tb.el.createChild({
46175 cls:'x-font-select',
46176 html: this.createFontOptions()
46179 editor.fontSelect.on('change', function(){
46180 var font = editor.fontSelect.dom.value;
46181 editor.relayCmd('fontname', font);
46182 editor.deferFocus();
46186 editor.fontSelect.dom,
46192 if(!this.disable.formats){
46193 this.formatCombo = new Roo.form.ComboBox({
46194 store: new Roo.data.SimpleStore({
46197 data : this.formats // from states.js
46201 //autoCreate : {tag: "div", size: "20"},
46202 displayField:'tag',
46206 triggerAction: 'all',
46207 emptyText:'Add tag',
46208 selectOnFocus:true,
46211 'select': function(c, r, i) {
46212 editorcore.insertTag(r.get('tag'));
46218 tb.addField(this.formatCombo);
46222 if(!this.disable.format){
46227 btn('strikethrough')
46230 if(!this.disable.fontSize){
46235 btn('increasefontsize', false, editorcore.adjustFont),
46236 btn('decreasefontsize', false, editorcore.adjustFont)
46241 if(!this.disable.colors){
46244 id:editorcore.frameId +'-forecolor',
46245 cls:'x-btn-icon x-edit-forecolor',
46246 clickEvent:'mousedown',
46247 tooltip: this.buttonTips['forecolor'] || undefined,
46249 menu : new Roo.menu.ColorMenu({
46250 allowReselect: true,
46251 focus: Roo.emptyFn,
46254 selectHandler: function(cp, color){
46255 editorcore.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
46256 editor.deferFocus();
46259 clickEvent:'mousedown'
46262 id:editorcore.frameId +'backcolor',
46263 cls:'x-btn-icon x-edit-backcolor',
46264 clickEvent:'mousedown',
46265 tooltip: this.buttonTips['backcolor'] || undefined,
46267 menu : new Roo.menu.ColorMenu({
46268 focus: Roo.emptyFn,
46271 allowReselect: true,
46272 selectHandler: function(cp, color){
46274 editorcore.execCmd('useCSS', false);
46275 editorcore.execCmd('hilitecolor', color);
46276 editorcore.execCmd('useCSS', true);
46277 editor.deferFocus();
46279 editorcore.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
46280 Roo.isSafari || Roo.isIE ? '#'+color : color);
46281 editor.deferFocus();
46285 clickEvent:'mousedown'
46290 // now add all the items...
46293 if(!this.disable.alignments){
46296 btn('justifyleft'),
46297 btn('justifycenter'),
46298 btn('justifyright')
46302 //if(!Roo.isSafari){
46303 if(!this.disable.links){
46306 btn('createlink', false, this.createLink) /// MOVE TO HERE?!!?!?!?!
46310 if(!this.disable.lists){
46313 btn('insertorderedlist'),
46314 btn('insertunorderedlist')
46317 if(!this.disable.sourceEdit){
46320 btn('sourceedit', true, function(btn){
46321 this.toggleSourceEdit(btn.pressed);
46328 // special menu.. - needs to be tidied up..
46329 if (!this.disable.special) {
46332 cls: 'x-edit-none',
46338 for (var i =0; i < this.specialChars.length; i++) {
46339 smenu.menu.items.push({
46341 html: this.specialChars[i],
46342 handler: function(a,b) {
46343 editorcore.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
46344 //editor.insertAtCursor(a.html);
46358 if (!this.disable.cleanStyles) {
46360 cls: 'x-btn-icon x-btn-clear',
46366 for (var i =0; i < this.cleanStyles.length; i++) {
46367 cmenu.menu.items.push({
46368 actiontype : this.cleanStyles[i],
46369 html: 'Remove ' + this.cleanStyles[i],
46370 handler: function(a,b) {
46373 var c = Roo.get(editorcore.doc.body);
46374 c.select('[style]').each(function(s) {
46375 s.dom.style.removeProperty(a.actiontype);
46377 editorcore.syncValue();
46382 cmenu.menu.items.push({
46383 actiontype : 'tablewidths',
46384 html: 'Remove Table Widths',
46385 handler: function(a,b) {
46386 editorcore.cleanTableWidths();
46387 editorcore.syncValue();
46391 cmenu.menu.items.push({
46392 actiontype : 'word',
46393 html: 'Remove MS Word Formating',
46394 handler: function(a,b) {
46395 editorcore.cleanWord();
46396 editorcore.syncValue();
46401 cmenu.menu.items.push({
46402 actiontype : 'all',
46403 html: 'Remove All Styles',
46404 handler: function(a,b) {
46406 var c = Roo.get(editorcore.doc.body);
46407 c.select('[style]').each(function(s) {
46408 s.dom.removeAttribute('style');
46410 editorcore.syncValue();
46415 cmenu.menu.items.push({
46416 actiontype : 'all',
46417 html: 'Remove All CSS Classes',
46418 handler: function(a,b) {
46420 var c = Roo.get(editorcore.doc.body);
46421 c.select('[class]').each(function(s) {
46422 s.dom.removeAttribute('class');
46424 editorcore.cleanWord();
46425 editorcore.syncValue();
46430 cmenu.menu.items.push({
46431 actiontype : 'tidy',
46432 html: 'Tidy HTML Source',
46433 handler: function(a,b) {
46434 editorcore.doc.body.innerHTML = editorcore.domToHTML();
46435 editorcore.syncValue();
46444 if (!this.disable.specialElements) {
46447 cls: 'x-edit-none',
46452 for (var i =0; i < this.specialElements.length; i++) {
46453 semenu.menu.items.push(
46455 handler: function(a,b) {
46456 editor.insertAtCursor(this.ihtml);
46458 }, this.specialElements[i])
46470 for(var i =0; i< this.btns.length;i++) {
46471 var b = Roo.factory(this.btns[i],Roo.form);
46472 b.cls = 'x-edit-none';
46474 if(typeof(this.btns[i].cls) != 'undefined' && this.btns[i].cls.indexOf('x-init-enable') !== -1){
46475 b.cls += ' x-init-enable';
46478 b.scope = editorcore;
46486 // disable everything...
46488 this.tb.items.each(function(item){
46491 item.id != editorcore.frameId+ '-sourceedit' &&
46492 (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)
46498 this.rendered = true;
46500 // the all the btns;
46501 editor.on('editorevent', this.updateToolbar, this);
46502 // other toolbars need to implement this..
46503 //editor.on('editmodechange', this.updateToolbar, this);
46507 relayBtnCmd : function(btn) {
46508 this.editorcore.relayCmd(btn.cmd);
46510 // private used internally
46511 createLink : function(){
46512 Roo.log("create link?");
46513 var url = prompt(this.createLinkText, this.defaultLinkValue);
46514 if(url && url != 'http:/'+'/'){
46515 this.editorcore.relayCmd('createlink', url);
46521 * Protected method that will not generally be called directly. It triggers
46522 * a toolbar update by reading the markup state of the current selection in the editor.
46524 updateToolbar: function(){
46526 if(!this.editorcore.activated){
46527 this.editor.onFirstFocus();
46531 var btns = this.tb.items.map,
46532 doc = this.editorcore.doc,
46533 frameId = this.editorcore.frameId;
46535 if(!this.disable.font && !Roo.isSafari){
46537 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
46538 if(name != this.fontSelect.dom.value){
46539 this.fontSelect.dom.value = name;
46543 if(!this.disable.format){
46544 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
46545 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
46546 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
46547 btns[frameId + '-strikethrough'].toggle(doc.queryCommandState('strikethrough'));
46549 if(!this.disable.alignments){
46550 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
46551 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
46552 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
46554 if(!Roo.isSafari && !this.disable.lists){
46555 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
46556 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
46559 var ans = this.editorcore.getAllAncestors();
46560 if (this.formatCombo) {
46563 var store = this.formatCombo.store;
46564 this.formatCombo.setValue("");
46565 for (var i =0; i < ans.length;i++) {
46566 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
46568 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
46576 // hides menus... - so this cant be on a menu...
46577 Roo.menu.MenuMgr.hideAll();
46579 //this.editorsyncValue();
46583 createFontOptions : function(){
46584 var buf = [], fs = this.fontFamilies, ff, lc;
46588 for(var i = 0, len = fs.length; i< len; i++){
46590 lc = ff.toLowerCase();
46592 '<option value="',lc,'" style="font-family:',ff,';"',
46593 (this.defaultFont == lc ? ' selected="true">' : '>'),
46598 return buf.join('');
46601 toggleSourceEdit : function(sourceEditMode){
46603 Roo.log("toolbar toogle");
46604 if(sourceEditMode === undefined){
46605 sourceEditMode = !this.sourceEditMode;
46607 this.sourceEditMode = sourceEditMode === true;
46608 var btn = this.tb.items.get(this.editorcore.frameId +'-sourceedit');
46609 // just toggle the button?
46610 if(btn.pressed !== this.sourceEditMode){
46611 btn.toggle(this.sourceEditMode);
46615 if(sourceEditMode){
46616 Roo.log("disabling buttons");
46617 this.tb.items.each(function(item){
46618 if(item.cmd != 'sourceedit' && (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)){
46624 Roo.log("enabling buttons");
46625 if(this.editorcore.initialized){
46626 this.tb.items.each(function(item){
46632 Roo.log("calling toggole on editor");
46633 // tell the editor that it's been pressed..
46634 this.editor.toggleSourceEdit(sourceEditMode);
46638 * Object collection of toolbar tooltips for the buttons in the editor. The key
46639 * is the command id associated with that button and the value is a valid QuickTips object.
46644 title: 'Bold (Ctrl+B)',
46645 text: 'Make the selected text bold.',
46646 cls: 'x-html-editor-tip'
46649 title: 'Italic (Ctrl+I)',
46650 text: 'Make the selected text italic.',
46651 cls: 'x-html-editor-tip'
46659 title: 'Bold (Ctrl+B)',
46660 text: 'Make the selected text bold.',
46661 cls: 'x-html-editor-tip'
46664 title: 'Italic (Ctrl+I)',
46665 text: 'Make the selected text italic.',
46666 cls: 'x-html-editor-tip'
46669 title: 'Underline (Ctrl+U)',
46670 text: 'Underline the selected text.',
46671 cls: 'x-html-editor-tip'
46674 title: 'Strikethrough',
46675 text: 'Strikethrough the selected text.',
46676 cls: 'x-html-editor-tip'
46678 increasefontsize : {
46679 title: 'Grow Text',
46680 text: 'Increase the font size.',
46681 cls: 'x-html-editor-tip'
46683 decreasefontsize : {
46684 title: 'Shrink Text',
46685 text: 'Decrease the font size.',
46686 cls: 'x-html-editor-tip'
46689 title: 'Text Highlight Color',
46690 text: 'Change the background color of the selected text.',
46691 cls: 'x-html-editor-tip'
46694 title: 'Font Color',
46695 text: 'Change the color of the selected text.',
46696 cls: 'x-html-editor-tip'
46699 title: 'Align Text Left',
46700 text: 'Align text to the left.',
46701 cls: 'x-html-editor-tip'
46704 title: 'Center Text',
46705 text: 'Center text in the editor.',
46706 cls: 'x-html-editor-tip'
46709 title: 'Align Text Right',
46710 text: 'Align text to the right.',
46711 cls: 'x-html-editor-tip'
46713 insertunorderedlist : {
46714 title: 'Bullet List',
46715 text: 'Start a bulleted list.',
46716 cls: 'x-html-editor-tip'
46718 insertorderedlist : {
46719 title: 'Numbered List',
46720 text: 'Start a numbered list.',
46721 cls: 'x-html-editor-tip'
46724 title: 'Hyperlink',
46725 text: 'Make the selected text a hyperlink.',
46726 cls: 'x-html-editor-tip'
46729 title: 'Source Edit',
46730 text: 'Switch to source editing mode.',
46731 cls: 'x-html-editor-tip'
46735 onDestroy : function(){
46738 this.tb.items.each(function(item){
46740 item.menu.removeAll();
46742 item.menu.el.destroy();
46750 onFirstFocus: function() {
46751 this.tb.items.each(function(item){
46760 // <script type="text/javascript">
46763 * Ext JS Library 1.1.1
46764 * Copyright(c) 2006-2007, Ext JS, LLC.
46771 * @class Roo.form.HtmlEditor.ToolbarContext
46776 new Roo.form.HtmlEditor({
46779 { xtype: 'ToolbarStandard', styles : {} }
46780 { xtype: 'ToolbarContext', disable : {} }
46786 * @config : {Object} disable List of elements to disable.. (not done yet.)
46787 * @config : {Object} styles Map of styles available.
46791 Roo.form.HtmlEditor.ToolbarContext = function(config)
46794 Roo.apply(this, config);
46795 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
46796 // dont call parent... till later.
46797 this.styles = this.styles || {};
46802 Roo.form.HtmlEditor.ToolbarContext.types = {
46814 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
46880 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
46885 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
46895 style : 'fontFamily',
46896 displayField: 'display',
46897 optname : 'font-family',
46946 // should we really allow this??
46947 // should this just be
46958 style : 'fontFamily',
46959 displayField: 'display',
46960 optname : 'font-family',
46967 style : 'fontFamily',
46968 displayField: 'display',
46969 optname : 'font-family',
46976 style : 'fontFamily',
46977 displayField: 'display',
46978 optname : 'font-family',
46989 // this should be configurable.. - you can either set it up using stores, or modify options somehwere..
46990 Roo.form.HtmlEditor.ToolbarContext.stores = false;
46992 Roo.form.HtmlEditor.ToolbarContext.options = {
46994 [ 'Helvetica,Arial,sans-serif', 'Helvetica'],
46995 [ 'Courier New', 'Courier New'],
46996 [ 'Tahoma', 'Tahoma'],
46997 [ 'Times New Roman,serif', 'Times'],
46998 [ 'Verdana','Verdana' ]
47002 // fixme - these need to be configurable..
47005 //Roo.form.HtmlEditor.ToolbarContext.types
47008 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
47015 editorcore : false,
47017 * @cfg {Object} disable List of toolbar elements to disable
47022 * @cfg {Object} styles List of styles
47023 * eg. { '*' : [ 'headline' ] , 'TD' : [ 'underline', 'double-underline' ] }
47025 * These must be defined in the page, so they get rendered correctly..
47036 init : function(editor)
47038 this.editor = editor;
47039 this.editorcore = editor.editorcore ? editor.editorcore : editor;
47040 var editorcore = this.editorcore;
47042 var fid = editorcore.frameId;
47044 function btn(id, toggle, handler){
47045 var xid = fid + '-'+ id ;
47049 cls : 'x-btn-icon x-edit-'+id,
47050 enableToggle:toggle !== false,
47051 scope: editorcore, // was editor...
47052 handler:handler||editorcore.relayBtnCmd,
47053 clickEvent:'mousedown',
47054 tooltip: etb.buttonTips[id] || undefined, ///tips ???
47058 // create a new element.
47059 var wdiv = editor.wrap.createChild({
47061 }, editor.wrap.dom.firstChild.nextSibling, true);
47063 // can we do this more than once??
47065 // stop form submits
47068 // disable everything...
47069 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
47070 this.toolbars = {};
47072 for (var i in ty) {
47074 this.toolbars[i] = this.buildToolbar(ty[i],i);
47076 this.tb = this.toolbars.BODY;
47078 this.buildFooter();
47079 this.footer.show();
47080 editor.on('hide', function( ) { this.footer.hide() }, this);
47081 editor.on('show', function( ) { this.footer.show() }, this);
47084 this.rendered = true;
47086 // the all the btns;
47087 editor.on('editorevent', this.updateToolbar, this);
47088 // other toolbars need to implement this..
47089 //editor.on('editmodechange', this.updateToolbar, this);
47095 * Protected method that will not generally be called directly. It triggers
47096 * a toolbar update by reading the markup state of the current selection in the editor.
47098 * Note you can force an update by calling on('editorevent', scope, false)
47100 updateToolbar: function(editor,ev,sel){
47103 // capture mouse up - this is handy for selecting images..
47104 // perhaps should go somewhere else...
47105 if(!this.editorcore.activated){
47106 this.editor.onFirstFocus();
47112 // http://developer.yahoo.com/yui/docs/simple-editor.js.html
47113 // selectNode - might want to handle IE?
47115 (ev.type == 'mouseup' || ev.type == 'click' ) &&
47116 ev.target && ev.target.tagName == 'IMG') {
47117 // they have click on an image...
47118 // let's see if we can change the selection...
47121 var nodeRange = sel.ownerDocument.createRange();
47123 nodeRange.selectNode(sel);
47125 nodeRange.selectNodeContents(sel);
47127 //nodeRange.collapse(true);
47128 var s = this.editorcore.win.getSelection();
47129 s.removeAllRanges();
47130 s.addRange(nodeRange);
47134 var updateFooter = sel ? false : true;
47137 var ans = this.editorcore.getAllAncestors();
47140 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
47143 sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editorcore.doc.body;
47144 sel = sel ? sel : this.editorcore.doc.body;
47145 sel = sel.tagName.length ? sel : this.editorcore.doc.body;
47148 // pick a menu that exists..
47149 var tn = sel.tagName.toUpperCase();
47150 //sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
47152 tn = sel.tagName.toUpperCase();
47154 var lastSel = this.tb.selectedNode;
47156 this.tb.selectedNode = sel;
47158 // if current menu does not match..
47160 if ((this.tb.name != tn) || (lastSel != this.tb.selectedNode) || ev === false) {
47163 ///console.log("show: " + tn);
47164 this.tb = typeof(ty[tn]) != 'undefined' ? this.toolbars[tn] : this.toolbars['*'];
47167 this.tb.items.first().el.innerHTML = tn + ': ';
47170 // update attributes
47171 if (this.tb.fields) {
47172 this.tb.fields.each(function(e) {
47174 e.setValue(sel.style[e.stylename]);
47177 e.setValue(sel.getAttribute(e.attrname));
47181 var hasStyles = false;
47182 for(var i in this.styles) {
47189 var st = this.tb.fields.item(0);
47191 st.store.removeAll();
47194 var cn = sel.className.split(/\s+/);
47197 if (this.styles['*']) {
47199 Roo.each(this.styles['*'], function(v) {
47200 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
47203 if (this.styles[tn]) {
47204 Roo.each(this.styles[tn], function(v) {
47205 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
47209 st.store.loadData(avs);
47213 // flag our selected Node.
47214 this.tb.selectedNode = sel;
47217 Roo.menu.MenuMgr.hideAll();
47221 if (!updateFooter) {
47222 //this.footDisp.dom.innerHTML = '';
47225 // update the footer
47229 this.footerEls = ans.reverse();
47230 Roo.each(this.footerEls, function(a,i) {
47231 if (!a) { return; }
47232 html += html.length ? ' > ' : '';
47234 html += '<span class="x-ed-loc-' + i + '">' + a.tagName + '</span>';
47239 var sz = this.footDisp.up('td').getSize();
47240 this.footDisp.dom.style.width = (sz.width -10) + 'px';
47241 this.footDisp.dom.style.marginLeft = '5px';
47243 this.footDisp.dom.style.overflow = 'hidden';
47245 this.footDisp.dom.innerHTML = html;
47247 //this.editorsyncValue();
47254 onDestroy : function(){
47257 this.tb.items.each(function(item){
47259 item.menu.removeAll();
47261 item.menu.el.destroy();
47269 onFirstFocus: function() {
47270 // need to do this for all the toolbars..
47271 this.tb.items.each(function(item){
47275 buildToolbar: function(tlist, nm)
47277 var editor = this.editor;
47278 var editorcore = this.editorcore;
47279 // create a new element.
47280 var wdiv = editor.wrap.createChild({
47282 }, editor.wrap.dom.firstChild.nextSibling, true);
47285 var tb = new Roo.Toolbar(wdiv);
47288 tb.add(nm+ ": ");
47291 for(var i in this.styles) {
47296 if (styles && styles.length) {
47298 // this needs a multi-select checkbox...
47299 tb.addField( new Roo.form.ComboBox({
47300 store: new Roo.data.SimpleStore({
47302 fields: ['val', 'selected'],
47305 name : '-roo-edit-className',
47306 attrname : 'className',
47307 displayField: 'val',
47311 triggerAction: 'all',
47312 emptyText:'Select Style',
47313 selectOnFocus:true,
47316 'select': function(c, r, i) {
47317 // initial support only for on class per el..
47318 tb.selectedNode.className = r ? r.get('val') : '';
47319 editorcore.syncValue();
47326 var tbc = Roo.form.HtmlEditor.ToolbarContext;
47327 var tbops = tbc.options;
47329 for (var i in tlist) {
47331 var item = tlist[i];
47332 tb.add(item.title + ": ");
47335 //optname == used so you can configure the options available..
47336 var opts = item.opts ? item.opts : false;
47337 if (item.optname) {
47338 opts = tbops[item.optname];
47343 // opts == pulldown..
47344 tb.addField( new Roo.form.ComboBox({
47345 store: typeof(tbc.stores[i]) != 'undefined' ? Roo.factory(tbc.stores[i],Roo.data) : new Roo.data.SimpleStore({
47347 fields: ['val', 'display'],
47350 name : '-roo-edit-' + i,
47352 stylename : item.style ? item.style : false,
47353 displayField: item.displayField ? item.displayField : 'val',
47354 valueField : 'val',
47356 mode: typeof(tbc.stores[i]) != 'undefined' ? 'remote' : 'local',
47358 triggerAction: 'all',
47359 emptyText:'Select',
47360 selectOnFocus:true,
47361 width: item.width ? item.width : 130,
47363 'select': function(c, r, i) {
47365 tb.selectedNode.style[c.stylename] = r.get('val');
47368 tb.selectedNode.setAttribute(c.attrname, r.get('val'));
47377 tb.addField( new Roo.form.TextField({
47380 //allowBlank:false,
47385 tb.addField( new Roo.form.TextField({
47386 name: '-roo-edit-' + i,
47393 'change' : function(f, nv, ov) {
47394 tb.selectedNode.setAttribute(f.attrname, nv);
47395 editorcore.syncValue();
47408 text: 'Stylesheets',
47411 click : function ()
47413 _this.editor.fireEvent('stylesheetsclick', _this.editor);
47421 text: 'Remove Tag',
47424 click : function ()
47427 // undo does not work.
47429 var sn = tb.selectedNode;
47431 var pn = sn.parentNode;
47433 var stn = sn.childNodes[0];
47434 var en = sn.childNodes[sn.childNodes.length - 1 ];
47435 while (sn.childNodes.length) {
47436 var node = sn.childNodes[0];
47437 sn.removeChild(node);
47439 pn.insertBefore(node, sn);
47442 pn.removeChild(sn);
47443 var range = editorcore.createRange();
47445 range.setStart(stn,0);
47446 range.setEnd(en,0); //????
47447 //range.selectNode(sel);
47450 var selection = editorcore.getSelection();
47451 selection.removeAllRanges();
47452 selection.addRange(range);
47456 //_this.updateToolbar(null, null, pn);
47457 _this.updateToolbar(null, null, null);
47458 _this.footDisp.dom.innerHTML = '';
47468 tb.el.on('click', function(e){
47469 e.preventDefault(); // what does this do?
47471 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
47474 // dont need to disable them... as they will get hidden
47479 buildFooter : function()
47482 var fel = this.editor.wrap.createChild();
47483 this.footer = new Roo.Toolbar(fel);
47484 // toolbar has scrolly on left / right?
47485 var footDisp= new Roo.Toolbar.Fill();
47491 handler : function() {
47492 _t.footDisp.scrollTo('left',0,true)
47496 this.footer.add( footDisp );
47501 handler : function() {
47503 _t.footDisp.select('span').last().scrollIntoView(_t.footDisp,true);
47507 var fel = Roo.get(footDisp.el);
47508 fel.addClass('x-editor-context');
47509 this.footDispWrap = fel;
47510 this.footDispWrap.overflow = 'hidden';
47512 this.footDisp = fel.createChild();
47513 this.footDispWrap.on('click', this.onContextClick, this)
47517 onContextClick : function (ev,dom)
47519 ev.preventDefault();
47520 var cn = dom.className;
47522 if (!cn.match(/x-ed-loc-/)) {
47525 var n = cn.split('-').pop();
47526 var ans = this.footerEls;
47530 var range = this.editorcore.createRange();
47532 range.selectNodeContents(sel);
47533 //range.selectNode(sel);
47536 var selection = this.editorcore.getSelection();
47537 selection.removeAllRanges();
47538 selection.addRange(range);
47542 this.updateToolbar(null, null, sel);
47559 * Ext JS Library 1.1.1
47560 * Copyright(c) 2006-2007, Ext JS, LLC.
47562 * Originally Released Under LGPL - original licence link has changed is not relivant.
47565 * <script type="text/javascript">
47569 * @class Roo.form.BasicForm
47570 * @extends Roo.util.Observable
47571 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
47573 * @param {String/HTMLElement/Roo.Element} el The form element or its id
47574 * @param {Object} config Configuration options
47576 Roo.form.BasicForm = function(el, config){
47577 this.allItems = [];
47578 this.childForms = [];
47579 Roo.apply(this, config);
47581 * The Roo.form.Field items in this form.
47582 * @type MixedCollection
47586 this.items = new Roo.util.MixedCollection(false, function(o){
47587 return o.id || (o.id = Roo.id());
47591 * @event beforeaction
47592 * Fires before any action is performed. Return false to cancel the action.
47593 * @param {Form} this
47594 * @param {Action} action The action to be performed
47596 beforeaction: true,
47598 * @event actionfailed
47599 * Fires when an action fails.
47600 * @param {Form} this
47601 * @param {Action} action The action that failed
47603 actionfailed : true,
47605 * @event actioncomplete
47606 * Fires when an action is completed.
47607 * @param {Form} this
47608 * @param {Action} action The action that completed
47610 actioncomplete : true
47615 Roo.form.BasicForm.superclass.constructor.call(this);
47617 Roo.form.BasicForm.popover.apply();
47620 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
47622 * @cfg {String} method
47623 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
47626 * @cfg {DataReader} reader
47627 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
47628 * This is optional as there is built-in support for processing JSON.
47631 * @cfg {DataReader} errorReader
47632 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
47633 * This is completely optional as there is built-in support for processing JSON.
47636 * @cfg {String} url
47637 * The URL to use for form actions if one isn't supplied in the action options.
47640 * @cfg {Boolean} fileUpload
47641 * Set to true if this form is a file upload.
47645 * @cfg {Object} baseParams
47646 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
47651 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
47656 activeAction : null,
47659 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
47660 * or setValues() data instead of when the form was first created.
47662 trackResetOnLoad : false,
47666 * childForms - used for multi-tab forms
47669 childForms : false,
47672 * allItems - full list of fields.
47678 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
47679 * element by passing it or its id or mask the form itself by passing in true.
47682 waitMsgTarget : false,
47687 disableMask : false,
47690 * @cfg {Boolean} errorMask (true|false) default false
47695 * @cfg {Number} maskOffset Default 100
47700 initEl : function(el){
47701 this.el = Roo.get(el);
47702 this.id = this.el.id || Roo.id();
47703 this.el.on('submit', this.onSubmit, this);
47704 this.el.addClass('x-form');
47708 onSubmit : function(e){
47713 * Returns true if client-side validation on the form is successful.
47716 isValid : function(){
47718 var target = false;
47719 this.items.each(function(f){
47726 if(!target && f.el.isVisible(true)){
47731 if(this.errorMask && !valid){
47732 Roo.form.BasicForm.popover.mask(this, target);
47738 * Returns array of invalid form fields.
47742 invalidFields : function()
47745 this.items.each(function(f){
47758 * DEPRICATED Returns true if any fields in this form have changed since their original load.
47761 isDirty : function(){
47763 this.items.each(function(f){
47773 * Returns true if any fields in this form have changed since their original load. (New version)
47777 hasChanged : function()
47780 this.items.each(function(f){
47781 if(f.hasChanged()){
47790 * Resets all hasChanged to 'false' -
47791 * The old 'isDirty' used 'original value..' however this breaks reset() and a few other things.
47792 * So hasChanged storage is only to be used for this purpose
47795 resetHasChanged : function()
47797 this.items.each(function(f){
47798 f.resetHasChanged();
47805 * Performs a predefined action (submit or load) or custom actions you define on this form.
47806 * @param {String} actionName The name of the action type
47807 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
47808 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
47809 * accept other config options):
47811 Property Type Description
47812 ---------------- --------------- ----------------------------------------------------------------------------------
47813 url String The url for the action (defaults to the form's url)
47814 method String The form method to use (defaults to the form's method, or POST if not defined)
47815 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
47816 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
47817 validate the form on the client (defaults to false)
47819 * @return {BasicForm} this
47821 doAction : function(action, options){
47822 if(typeof action == 'string'){
47823 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
47825 if(this.fireEvent('beforeaction', this, action) !== false){
47826 this.beforeAction(action);
47827 action.run.defer(100, action);
47833 * Shortcut to do a submit action.
47834 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
47835 * @return {BasicForm} this
47837 submit : function(options){
47838 this.doAction('submit', options);
47843 * Shortcut to do a load action.
47844 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
47845 * @return {BasicForm} this
47847 load : function(options){
47848 this.doAction('load', options);
47853 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
47854 * @param {Record} record The record to edit
47855 * @return {BasicForm} this
47857 updateRecord : function(record){
47858 record.beginEdit();
47859 var fs = record.fields;
47860 fs.each(function(f){
47861 var field = this.findField(f.name);
47863 record.set(f.name, field.getValue());
47871 * Loads an Roo.data.Record into this form.
47872 * @param {Record} record The record to load
47873 * @return {BasicForm} this
47875 loadRecord : function(record){
47876 this.setValues(record.data);
47881 beforeAction : function(action){
47882 var o = action.options;
47884 if(!this.disableMask) {
47885 if(this.waitMsgTarget === true){
47886 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
47887 }else if(this.waitMsgTarget){
47888 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
47889 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
47891 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
47899 afterAction : function(action, success){
47900 this.activeAction = null;
47901 var o = action.options;
47903 if(!this.disableMask) {
47904 if(this.waitMsgTarget === true){
47906 }else if(this.waitMsgTarget){
47907 this.waitMsgTarget.unmask();
47909 Roo.MessageBox.updateProgress(1);
47910 Roo.MessageBox.hide();
47918 Roo.callback(o.success, o.scope, [this, action]);
47919 this.fireEvent('actioncomplete', this, action);
47923 // failure condition..
47924 // we have a scenario where updates need confirming.
47925 // eg. if a locking scenario exists..
47926 // we look for { errors : { needs_confirm : true }} in the response.
47928 (typeof(action.result) != 'undefined') &&
47929 (typeof(action.result.errors) != 'undefined') &&
47930 (typeof(action.result.errors.needs_confirm) != 'undefined')
47933 Roo.MessageBox.confirm(
47934 "Change requires confirmation",
47935 action.result.errorMsg,
47940 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
47950 Roo.callback(o.failure, o.scope, [this, action]);
47951 // show an error message if no failed handler is set..
47952 if (!this.hasListener('actionfailed')) {
47953 Roo.MessageBox.alert("Error",
47954 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
47955 action.result.errorMsg :
47956 "Saving Failed, please check your entries or try again"
47960 this.fireEvent('actionfailed', this, action);
47966 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
47967 * @param {String} id The value to search for
47970 findField : function(id){
47971 var field = this.items.get(id);
47973 this.items.each(function(f){
47974 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
47980 return field || null;
47984 * Add a secondary form to this one,
47985 * Used to provide tabbed forms. One form is primary, with hidden values
47986 * which mirror the elements from the other forms.
47988 * @param {Roo.form.Form} form to add.
47991 addForm : function(form)
47994 if (this.childForms.indexOf(form) > -1) {
47998 this.childForms.push(form);
48000 Roo.each(form.allItems, function (fe) {
48002 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
48003 if (this.findField(n)) { // already added..
48006 var add = new Roo.form.Hidden({
48009 add.render(this.el);
48016 * Mark fields in this form invalid in bulk.
48017 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
48018 * @return {BasicForm} this
48020 markInvalid : function(errors){
48021 if(errors instanceof Array){
48022 for(var i = 0, len = errors.length; i < len; i++){
48023 var fieldError = errors[i];
48024 var f = this.findField(fieldError.id);
48026 f.markInvalid(fieldError.msg);
48032 if(typeof errors[id] != 'function' && (field = this.findField(id))){
48033 field.markInvalid(errors[id]);
48037 Roo.each(this.childForms || [], function (f) {
48038 f.markInvalid(errors);
48045 * Set values for fields in this form in bulk.
48046 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
48047 * @return {BasicForm} this
48049 setValues : function(values){
48050 if(values instanceof Array){ // array of objects
48051 for(var i = 0, len = values.length; i < len; i++){
48053 var f = this.findField(v.id);
48055 f.setValue(v.value);
48056 if(this.trackResetOnLoad){
48057 f.originalValue = f.getValue();
48061 }else{ // object hash
48064 if(typeof values[id] != 'function' && (field = this.findField(id))){
48066 if (field.setFromData &&
48067 field.valueField &&
48068 field.displayField &&
48069 // combos' with local stores can
48070 // be queried via setValue()
48071 // to set their value..
48072 (field.store && !field.store.isLocal)
48076 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
48077 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
48078 field.setFromData(sd);
48081 field.setValue(values[id]);
48085 if(this.trackResetOnLoad){
48086 field.originalValue = field.getValue();
48091 this.resetHasChanged();
48094 Roo.each(this.childForms || [], function (f) {
48095 f.setValues(values);
48096 f.resetHasChanged();
48103 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
48104 * they are returned as an array.
48105 * @param {Boolean} asString
48108 getValues : function(asString){
48109 if (this.childForms) {
48110 // copy values from the child forms
48111 Roo.each(this.childForms, function (f) {
48112 this.setValues(f.getValues());
48117 if (typeof(FormData) != 'undefined' && asString !== true) {
48118 // this relies on a 'recent' version of chrome apparently...
48120 var fd = (new FormData(this.el.dom)).entries();
48122 var ent = fd.next();
48123 while (!ent.done) {
48124 ret[ent.value[0]] = ent.value[1]; // not sure how this will handle duplicates..
48135 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
48136 if(asString === true){
48139 return Roo.urlDecode(fs);
48143 * Returns the fields in this form as an object with key/value pairs.
48144 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
48147 getFieldValues : function(with_hidden)
48149 if (this.childForms) {
48150 // copy values from the child forms
48151 // should this call getFieldValues - probably not as we do not currently copy
48152 // hidden fields when we generate..
48153 Roo.each(this.childForms, function (f) {
48154 this.setValues(f.getValues());
48159 this.items.each(function(f){
48160 if (!f.getName()) {
48163 var v = f.getValue();
48164 if (f.inputType =='radio') {
48165 if (typeof(ret[f.getName()]) == 'undefined') {
48166 ret[f.getName()] = ''; // empty..
48169 if (!f.el.dom.checked) {
48173 v = f.el.dom.value;
48177 // not sure if this supported any more..
48178 if ((typeof(v) == 'object') && f.getRawValue) {
48179 v = f.getRawValue() ; // dates..
48181 // combo boxes where name != hiddenName...
48182 if (f.name != f.getName()) {
48183 ret[f.name] = f.getRawValue();
48185 ret[f.getName()] = v;
48192 * Clears all invalid messages in this form.
48193 * @return {BasicForm} this
48195 clearInvalid : function(){
48196 this.items.each(function(f){
48200 Roo.each(this.childForms || [], function (f) {
48209 * Resets this form.
48210 * @return {BasicForm} this
48212 reset : function(){
48213 this.items.each(function(f){
48217 Roo.each(this.childForms || [], function (f) {
48220 this.resetHasChanged();
48226 * Add Roo.form components to this form.
48227 * @param {Field} field1
48228 * @param {Field} field2 (optional)
48229 * @param {Field} etc (optional)
48230 * @return {BasicForm} this
48233 this.items.addAll(Array.prototype.slice.call(arguments, 0));
48239 * Removes a field from the items collection (does NOT remove its markup).
48240 * @param {Field} field
48241 * @return {BasicForm} this
48243 remove : function(field){
48244 this.items.remove(field);
48249 * Looks at the fields in this form, checks them for an id attribute,
48250 * and calls applyTo on the existing dom element with that id.
48251 * @return {BasicForm} this
48253 render : function(){
48254 this.items.each(function(f){
48255 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
48263 * Calls {@link Ext#apply} for all fields in this form with the passed object.
48264 * @param {Object} values
48265 * @return {BasicForm} this
48267 applyToFields : function(o){
48268 this.items.each(function(f){
48275 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
48276 * @param {Object} values
48277 * @return {BasicForm} this
48279 applyIfToFields : function(o){
48280 this.items.each(function(f){
48288 Roo.BasicForm = Roo.form.BasicForm;
48290 Roo.apply(Roo.form.BasicForm, {
48304 intervalID : false,
48310 if(this.isApplied){
48315 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
48316 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
48317 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
48318 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
48321 this.maskEl.top.enableDisplayMode("block");
48322 this.maskEl.left.enableDisplayMode("block");
48323 this.maskEl.bottom.enableDisplayMode("block");
48324 this.maskEl.right.enableDisplayMode("block");
48326 Roo.get(document.body).on('click', function(){
48330 Roo.get(document.body).on('touchstart', function(){
48334 this.isApplied = true
48337 mask : function(form, target)
48341 this.target = target;
48343 if(!this.form.errorMask || !target.el){
48347 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.x-layout-active-content', 100, true) || Roo.get(document.body);
48349 var ot = this.target.el.calcOffsetsTo(scrollable);
48351 var scrollTo = ot[1] - this.form.maskOffset;
48353 scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
48355 scrollable.scrollTo('top', scrollTo);
48357 var el = this.target.wrap || this.target.el;
48359 var box = el.getBox();
48361 this.maskEl.top.setStyle('position', 'absolute');
48362 this.maskEl.top.setStyle('z-index', 10000);
48363 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
48364 this.maskEl.top.setLeft(0);
48365 this.maskEl.top.setTop(0);
48366 this.maskEl.top.show();
48368 this.maskEl.left.setStyle('position', 'absolute');
48369 this.maskEl.left.setStyle('z-index', 10000);
48370 this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
48371 this.maskEl.left.setLeft(0);
48372 this.maskEl.left.setTop(box.y - this.padding);
48373 this.maskEl.left.show();
48375 this.maskEl.bottom.setStyle('position', 'absolute');
48376 this.maskEl.bottom.setStyle('z-index', 10000);
48377 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
48378 this.maskEl.bottom.setLeft(0);
48379 this.maskEl.bottom.setTop(box.bottom + this.padding);
48380 this.maskEl.bottom.show();
48382 this.maskEl.right.setStyle('position', 'absolute');
48383 this.maskEl.right.setStyle('z-index', 10000);
48384 this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
48385 this.maskEl.right.setLeft(box.right + this.padding);
48386 this.maskEl.right.setTop(box.y - this.padding);
48387 this.maskEl.right.show();
48389 this.intervalID = window.setInterval(function() {
48390 Roo.form.BasicForm.popover.unmask();
48393 window.onwheel = function(){ return false;};
48395 (function(){ this.isMasked = true; }).defer(500, this);
48399 unmask : function()
48401 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
48405 this.maskEl.top.setStyle('position', 'absolute');
48406 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
48407 this.maskEl.top.hide();
48409 this.maskEl.left.setStyle('position', 'absolute');
48410 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
48411 this.maskEl.left.hide();
48413 this.maskEl.bottom.setStyle('position', 'absolute');
48414 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
48415 this.maskEl.bottom.hide();
48417 this.maskEl.right.setStyle('position', 'absolute');
48418 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
48419 this.maskEl.right.hide();
48421 window.onwheel = function(){ return true;};
48423 if(this.intervalID){
48424 window.clearInterval(this.intervalID);
48425 this.intervalID = false;
48428 this.isMasked = false;
48436 * Ext JS Library 1.1.1
48437 * Copyright(c) 2006-2007, Ext JS, LLC.
48439 * Originally Released Under LGPL - original licence link has changed is not relivant.
48442 * <script type="text/javascript">
48446 * @class Roo.form.Form
48447 * @extends Roo.form.BasicForm
48448 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
48450 * @param {Object} config Configuration options
48452 Roo.form.Form = function(config){
48454 if (config.items) {
48455 xitems = config.items;
48456 delete config.items;
48460 Roo.form.Form.superclass.constructor.call(this, null, config);
48461 this.url = this.url || this.action;
48463 this.root = new Roo.form.Layout(Roo.applyIf({
48467 this.active = this.root;
48469 * Array of all the buttons that have been added to this form via {@link addButton}
48473 this.allItems = [];
48476 * @event clientvalidation
48477 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
48478 * @param {Form} this
48479 * @param {Boolean} valid true if the form has passed client-side validation
48481 clientvalidation: true,
48484 * Fires when the form is rendered
48485 * @param {Roo.form.Form} form
48490 if (this.progressUrl) {
48491 // push a hidden field onto the list of fields..
48495 name : 'UPLOAD_IDENTIFIER'
48500 Roo.each(xitems, this.addxtype, this);
48504 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
48506 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
48509 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
48512 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
48514 buttonAlign:'center',
48517 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
48522 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
48523 * This property cascades to child containers if not set.
48528 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
48529 * fires a looping event with that state. This is required to bind buttons to the valid
48530 * state using the config value formBind:true on the button.
48532 monitorValid : false,
48535 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
48540 * @cfg {String} progressUrl - Url to return progress data
48543 progressUrl : false,
48545 * @cfg {boolean|FormData} formData - true to use new 'FormData' post, or set to a new FormData({dom form}) Object, if
48546 * sending a formdata with extra parameters - eg uploaded elements.
48552 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
48553 * fields are added and the column is closed. If no fields are passed the column remains open
48554 * until end() is called.
48555 * @param {Object} config The config to pass to the column
48556 * @param {Field} field1 (optional)
48557 * @param {Field} field2 (optional)
48558 * @param {Field} etc (optional)
48559 * @return Column The column container object
48561 column : function(c){
48562 var col = new Roo.form.Column(c);
48564 if(arguments.length > 1){ // duplicate code required because of Opera
48565 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
48572 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
48573 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
48574 * until end() is called.
48575 * @param {Object} config The config to pass to the fieldset
48576 * @param {Field} field1 (optional)
48577 * @param {Field} field2 (optional)
48578 * @param {Field} etc (optional)
48579 * @return FieldSet The fieldset container object
48581 fieldset : function(c){
48582 var fs = new Roo.form.FieldSet(c);
48584 if(arguments.length > 1){ // duplicate code required because of Opera
48585 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
48592 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
48593 * fields are added and the container is closed. If no fields are passed the container remains open
48594 * until end() is called.
48595 * @param {Object} config The config to pass to the Layout
48596 * @param {Field} field1 (optional)
48597 * @param {Field} field2 (optional)
48598 * @param {Field} etc (optional)
48599 * @return Layout The container object
48601 container : function(c){
48602 var l = new Roo.form.Layout(c);
48604 if(arguments.length > 1){ // duplicate code required because of Opera
48605 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
48612 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
48613 * @param {Object} container A Roo.form.Layout or subclass of Layout
48614 * @return {Form} this
48616 start : function(c){
48617 // cascade label info
48618 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
48619 this.active.stack.push(c);
48620 c.ownerCt = this.active;
48626 * Closes the current open container
48627 * @return {Form} this
48630 if(this.active == this.root){
48633 this.active = this.active.ownerCt;
48638 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
48639 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
48640 * as the label of the field.
48641 * @param {Field} field1
48642 * @param {Field} field2 (optional)
48643 * @param {Field} etc. (optional)
48644 * @return {Form} this
48647 this.active.stack.push.apply(this.active.stack, arguments);
48648 this.allItems.push.apply(this.allItems,arguments);
48650 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
48651 if(a[i].isFormField){
48656 Roo.form.Form.superclass.add.apply(this, r);
48666 * Find any element that has been added to a form, using it's ID or name
48667 * This can include framesets, columns etc. along with regular fields..
48668 * @param {String} id - id or name to find.
48670 * @return {Element} e - or false if nothing found.
48672 findbyId : function(id)
48678 Roo.each(this.allItems, function(f){
48679 if (f.id == id || f.name == id ){
48690 * Render this form into the passed container. This should only be called once!
48691 * @param {String/HTMLElement/Element} container The element this component should be rendered into
48692 * @return {Form} this
48694 render : function(ct)
48700 var o = this.autoCreate || {
48702 method : this.method || 'POST',
48703 id : this.id || Roo.id()
48705 this.initEl(ct.createChild(o));
48707 this.root.render(this.el);
48711 this.items.each(function(f){
48712 f.render('x-form-el-'+f.id);
48715 if(this.buttons.length > 0){
48716 // tables are required to maintain order and for correct IE layout
48717 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
48718 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
48719 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
48721 var tr = tb.getElementsByTagName('tr')[0];
48722 for(var i = 0, len = this.buttons.length; i < len; i++) {
48723 var b = this.buttons[i];
48724 var td = document.createElement('td');
48725 td.className = 'x-form-btn-td';
48726 b.render(tr.appendChild(td));
48729 if(this.monitorValid){ // initialize after render
48730 this.startMonitoring();
48732 this.fireEvent('rendered', this);
48737 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
48738 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
48739 * object or a valid Roo.DomHelper element config
48740 * @param {Function} handler The function called when the button is clicked
48741 * @param {Object} scope (optional) The scope of the handler function
48742 * @return {Roo.Button}
48744 addButton : function(config, handler, scope){
48748 minWidth: this.minButtonWidth,
48751 if(typeof config == "string"){
48754 Roo.apply(bc, config);
48756 var btn = new Roo.Button(null, bc);
48757 this.buttons.push(btn);
48762 * Adds a series of form elements (using the xtype property as the factory method.
48763 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
48764 * @param {Object} config
48767 addxtype : function()
48769 var ar = Array.prototype.slice.call(arguments, 0);
48771 for(var i = 0; i < ar.length; i++) {
48773 continue; // skip -- if this happends something invalid got sent, we
48774 // should ignore it, as basically that interface element will not show up
48775 // and that should be pretty obvious!!
48778 if (Roo.form[ar[i].xtype]) {
48780 var fe = Roo.factory(ar[i], Roo.form);
48786 fe.store.form = this;
48791 this.allItems.push(fe);
48792 if (fe.items && fe.addxtype) {
48793 fe.addxtype.apply(fe, fe.items);
48803 // console.log('adding ' + ar[i].xtype);
48805 if (ar[i].xtype == 'Button') {
48806 //console.log('adding button');
48807 //console.log(ar[i]);
48808 this.addButton(ar[i]);
48809 this.allItems.push(fe);
48813 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
48814 alert('end is not supported on xtype any more, use items');
48816 // //console.log('adding end');
48824 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
48825 * option "monitorValid"
48827 startMonitoring : function(){
48830 Roo.TaskMgr.start({
48831 run : this.bindHandler,
48832 interval : this.monitorPoll || 200,
48839 * Stops monitoring of the valid state of this form
48841 stopMonitoring : function(){
48842 this.bound = false;
48846 bindHandler : function(){
48848 return false; // stops binding
48851 this.items.each(function(f){
48852 if(!f.isValid(true)){
48857 for(var i = 0, len = this.buttons.length; i < len; i++){
48858 var btn = this.buttons[i];
48859 if(btn.formBind === true && btn.disabled === valid){
48860 btn.setDisabled(!valid);
48863 this.fireEvent('clientvalidation', this, valid);
48877 Roo.Form = Roo.form.Form;
48880 * Ext JS Library 1.1.1
48881 * Copyright(c) 2006-2007, Ext JS, LLC.
48883 * Originally Released Under LGPL - original licence link has changed is not relivant.
48886 * <script type="text/javascript">
48889 // as we use this in bootstrap.
48890 Roo.namespace('Roo.form');
48892 * @class Roo.form.Action
48893 * Internal Class used to handle form actions
48895 * @param {Roo.form.BasicForm} el The form element or its id
48896 * @param {Object} config Configuration options
48901 // define the action interface
48902 Roo.form.Action = function(form, options){
48904 this.options = options || {};
48907 * Client Validation Failed
48910 Roo.form.Action.CLIENT_INVALID = 'client';
48912 * Server Validation Failed
48915 Roo.form.Action.SERVER_INVALID = 'server';
48917 * Connect to Server Failed
48920 Roo.form.Action.CONNECT_FAILURE = 'connect';
48922 * Reading Data from Server Failed
48925 Roo.form.Action.LOAD_FAILURE = 'load';
48927 Roo.form.Action.prototype = {
48929 failureType : undefined,
48930 response : undefined,
48931 result : undefined,
48933 // interface method
48934 run : function(options){
48938 // interface method
48939 success : function(response){
48943 // interface method
48944 handleResponse : function(response){
48948 // default connection failure
48949 failure : function(response){
48951 this.response = response;
48952 this.failureType = Roo.form.Action.CONNECT_FAILURE;
48953 this.form.afterAction(this, false);
48956 processResponse : function(response){
48957 this.response = response;
48958 if(!response.responseText){
48961 this.result = this.handleResponse(response);
48962 return this.result;
48965 // utility functions used internally
48966 getUrl : function(appendParams){
48967 var url = this.options.url || this.form.url || this.form.el.dom.action;
48969 var p = this.getParams();
48971 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
48977 getMethod : function(){
48978 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
48981 getParams : function(){
48982 var bp = this.form.baseParams;
48983 var p = this.options.params;
48985 if(typeof p == "object"){
48986 p = Roo.urlEncode(Roo.applyIf(p, bp));
48987 }else if(typeof p == 'string' && bp){
48988 p += '&' + Roo.urlEncode(bp);
48991 p = Roo.urlEncode(bp);
48996 createCallback : function(){
48998 success: this.success,
48999 failure: this.failure,
49001 timeout: (this.form.timeout*1000),
49002 upload: this.form.fileUpload ? this.success : undefined
49007 Roo.form.Action.Submit = function(form, options){
49008 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
49011 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
49014 haveProgress : false,
49015 uploadComplete : false,
49017 // uploadProgress indicator.
49018 uploadProgress : function()
49020 if (!this.form.progressUrl) {
49024 if (!this.haveProgress) {
49025 Roo.MessageBox.progress("Uploading", "Uploading");
49027 if (this.uploadComplete) {
49028 Roo.MessageBox.hide();
49032 this.haveProgress = true;
49034 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
49036 var c = new Roo.data.Connection();
49038 url : this.form.progressUrl,
49043 success : function(req){
49044 //console.log(data);
49048 rdata = Roo.decode(req.responseText)
49050 Roo.log("Invalid data from server..");
49054 if (!rdata || !rdata.success) {
49056 Roo.MessageBox.alert(Roo.encode(rdata));
49059 var data = rdata.data;
49061 if (this.uploadComplete) {
49062 Roo.MessageBox.hide();
49067 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
49068 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
49071 this.uploadProgress.defer(2000,this);
49074 failure: function(data) {
49075 Roo.log('progress url failed ');
49086 // run get Values on the form, so it syncs any secondary forms.
49087 this.form.getValues();
49089 var o = this.options;
49090 var method = this.getMethod();
49091 var isPost = method == 'POST';
49092 if(o.clientValidation === false || this.form.isValid()){
49094 if (this.form.progressUrl) {
49095 this.form.findField('UPLOAD_IDENTIFIER').setValue(
49096 (new Date() * 1) + '' + Math.random());
49101 Roo.Ajax.request(Roo.apply(this.createCallback(), {
49102 form:this.form.el.dom,
49103 url:this.getUrl(!isPost),
49105 params:isPost ? this.getParams() : null,
49106 isUpload: this.form.fileUpload,
49107 formData : this.form.formData
49110 this.uploadProgress();
49112 }else if (o.clientValidation !== false){ // client validation failed
49113 this.failureType = Roo.form.Action.CLIENT_INVALID;
49114 this.form.afterAction(this, false);
49118 success : function(response)
49120 this.uploadComplete= true;
49121 if (this.haveProgress) {
49122 Roo.MessageBox.hide();
49126 var result = this.processResponse(response);
49127 if(result === true || result.success){
49128 this.form.afterAction(this, true);
49132 this.form.markInvalid(result.errors);
49133 this.failureType = Roo.form.Action.SERVER_INVALID;
49135 this.form.afterAction(this, false);
49137 failure : function(response)
49139 this.uploadComplete= true;
49140 if (this.haveProgress) {
49141 Roo.MessageBox.hide();
49144 this.response = response;
49145 this.failureType = Roo.form.Action.CONNECT_FAILURE;
49146 this.form.afterAction(this, false);
49149 handleResponse : function(response){
49150 if(this.form.errorReader){
49151 var rs = this.form.errorReader.read(response);
49154 for(var i = 0, len = rs.records.length; i < len; i++) {
49155 var r = rs.records[i];
49156 errors[i] = r.data;
49159 if(errors.length < 1){
49163 success : rs.success,
49169 ret = Roo.decode(response.responseText);
49173 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
49183 Roo.form.Action.Load = function(form, options){
49184 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
49185 this.reader = this.form.reader;
49188 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
49193 Roo.Ajax.request(Roo.apply(
49194 this.createCallback(), {
49195 method:this.getMethod(),
49196 url:this.getUrl(false),
49197 params:this.getParams()
49201 success : function(response){
49203 var result = this.processResponse(response);
49204 if(result === true || !result.success || !result.data){
49205 this.failureType = Roo.form.Action.LOAD_FAILURE;
49206 this.form.afterAction(this, false);
49209 this.form.clearInvalid();
49210 this.form.setValues(result.data);
49211 this.form.afterAction(this, true);
49214 handleResponse : function(response){
49215 if(this.form.reader){
49216 var rs = this.form.reader.read(response);
49217 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
49219 success : rs.success,
49223 return Roo.decode(response.responseText);
49227 Roo.form.Action.ACTION_TYPES = {
49228 'load' : Roo.form.Action.Load,
49229 'submit' : Roo.form.Action.Submit
49232 * Ext JS Library 1.1.1
49233 * Copyright(c) 2006-2007, Ext JS, LLC.
49235 * Originally Released Under LGPL - original licence link has changed is not relivant.
49238 * <script type="text/javascript">
49242 * @class Roo.form.Layout
49243 * @extends Roo.Component
49244 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
49246 * @param {Object} config Configuration options
49248 Roo.form.Layout = function(config){
49250 if (config.items) {
49251 xitems = config.items;
49252 delete config.items;
49254 Roo.form.Layout.superclass.constructor.call(this, config);
49256 Roo.each(xitems, this.addxtype, this);
49260 Roo.extend(Roo.form.Layout, Roo.Component, {
49262 * @cfg {String/Object} autoCreate
49263 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
49266 * @cfg {String/Object/Function} style
49267 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
49268 * a function which returns such a specification.
49271 * @cfg {String} labelAlign
49272 * Valid values are "left," "top" and "right" (defaults to "left")
49275 * @cfg {Number} labelWidth
49276 * Fixed width in pixels of all field labels (defaults to undefined)
49279 * @cfg {Boolean} clear
49280 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
49284 * @cfg {String} labelSeparator
49285 * The separator to use after field labels (defaults to ':')
49287 labelSeparator : ':',
49289 * @cfg {Boolean} hideLabels
49290 * True to suppress the display of field labels in this layout (defaults to false)
49292 hideLabels : false,
49295 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
49300 onRender : function(ct, position){
49301 if(this.el){ // from markup
49302 this.el = Roo.get(this.el);
49303 }else { // generate
49304 var cfg = this.getAutoCreate();
49305 this.el = ct.createChild(cfg, position);
49308 this.el.applyStyles(this.style);
49310 if(this.labelAlign){
49311 this.el.addClass('x-form-label-'+this.labelAlign);
49313 if(this.hideLabels){
49314 this.labelStyle = "display:none";
49315 this.elementStyle = "padding-left:0;";
49317 if(typeof this.labelWidth == 'number'){
49318 this.labelStyle = "width:"+this.labelWidth+"px;";
49319 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
49321 if(this.labelAlign == 'top'){
49322 this.labelStyle = "width:auto;";
49323 this.elementStyle = "padding-left:0;";
49326 var stack = this.stack;
49327 var slen = stack.length;
49329 if(!this.fieldTpl){
49330 var t = new Roo.Template(
49331 '<div class="x-form-item {5}">',
49332 '<label for="{0}" style="{2}">{1}{4}</label>',
49333 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
49335 '</div><div class="x-form-clear-left"></div>'
49337 t.disableFormats = true;
49339 Roo.form.Layout.prototype.fieldTpl = t;
49341 for(var i = 0; i < slen; i++) {
49342 if(stack[i].isFormField){
49343 this.renderField(stack[i]);
49345 this.renderComponent(stack[i]);
49350 this.el.createChild({cls:'x-form-clear'});
49355 renderField : function(f){
49356 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
49359 f.labelStyle||this.labelStyle||'', //2
49360 this.elementStyle||'', //3
49361 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
49362 f.itemCls||this.itemCls||'' //5
49363 ], true).getPrevSibling());
49367 renderComponent : function(c){
49368 c.render(c.isLayout ? this.el : this.el.createChild());
49371 * Adds a object form elements (using the xtype property as the factory method.)
49372 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
49373 * @param {Object} config
49375 addxtype : function(o)
49377 // create the lement.
49378 o.form = this.form;
49379 var fe = Roo.factory(o, Roo.form);
49380 this.form.allItems.push(fe);
49381 this.stack.push(fe);
49383 if (fe.isFormField) {
49384 this.form.items.add(fe);
49392 * @class Roo.form.Column
49393 * @extends Roo.form.Layout
49394 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
49396 * @param {Object} config Configuration options
49398 Roo.form.Column = function(config){
49399 Roo.form.Column.superclass.constructor.call(this, config);
49402 Roo.extend(Roo.form.Column, Roo.form.Layout, {
49404 * @cfg {Number/String} width
49405 * The fixed width of the column in pixels or CSS value (defaults to "auto")
49408 * @cfg {String/Object} autoCreate
49409 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
49413 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
49416 onRender : function(ct, position){
49417 Roo.form.Column.superclass.onRender.call(this, ct, position);
49419 this.el.setWidth(this.width);
49426 * @class Roo.form.Row
49427 * @extends Roo.form.Layout
49428 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
49430 * @param {Object} config Configuration options
49434 Roo.form.Row = function(config){
49435 Roo.form.Row.superclass.constructor.call(this, config);
49438 Roo.extend(Roo.form.Row, Roo.form.Layout, {
49440 * @cfg {Number/String} width
49441 * The fixed width of the column in pixels or CSS value (defaults to "auto")
49444 * @cfg {Number/String} height
49445 * The fixed height of the column in pixels or CSS value (defaults to "auto")
49447 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
49451 onRender : function(ct, position){
49452 //console.log('row render');
49454 var t = new Roo.Template(
49455 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
49456 '<label for="{0}" style="{2}">{1}{4}</label>',
49457 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
49461 t.disableFormats = true;
49463 Roo.form.Layout.prototype.rowTpl = t;
49465 this.fieldTpl = this.rowTpl;
49467 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
49468 var labelWidth = 100;
49470 if ((this.labelAlign != 'top')) {
49471 if (typeof this.labelWidth == 'number') {
49472 labelWidth = this.labelWidth
49474 this.padWidth = 20 + labelWidth;
49478 Roo.form.Column.superclass.onRender.call(this, ct, position);
49480 this.el.setWidth(this.width);
49483 this.el.setHeight(this.height);
49488 renderField : function(f){
49489 f.fieldEl = this.fieldTpl.append(this.el, [
49490 f.id, f.fieldLabel,
49491 f.labelStyle||this.labelStyle||'',
49492 this.elementStyle||'',
49493 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
49494 f.itemCls||this.itemCls||'',
49495 f.width ? f.width + this.padWidth : 160 + this.padWidth
49502 * @class Roo.form.FieldSet
49503 * @extends Roo.form.Layout
49504 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
49506 * @param {Object} config Configuration options
49508 Roo.form.FieldSet = function(config){
49509 Roo.form.FieldSet.superclass.constructor.call(this, config);
49512 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
49514 * @cfg {String} legend
49515 * The text to display as the legend for the FieldSet (defaults to '')
49518 * @cfg {String/Object} autoCreate
49519 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
49523 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
49526 onRender : function(ct, position){
49527 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
49529 this.setLegend(this.legend);
49534 setLegend : function(text){
49536 this.el.child('legend').update(text);
49541 * Ext JS Library 1.1.1
49542 * Copyright(c) 2006-2007, Ext JS, LLC.
49544 * Originally Released Under LGPL - original licence link has changed is not relivant.
49547 * <script type="text/javascript">
49550 * @class Roo.form.VTypes
49551 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
49554 Roo.form.VTypes = function(){
49555 // closure these in so they are only created once.
49556 var alpha = /^[a-zA-Z_]+$/;
49557 var alphanum = /^[a-zA-Z0-9_]+$/;
49558 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
49559 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
49561 // All these messages and functions are configurable
49564 * The function used to validate email addresses
49565 * @param {String} value The email address
49567 'email' : function(v){
49568 return email.test(v);
49571 * The error text to display when the email validation function returns false
49574 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
49576 * The keystroke filter mask to be applied on email input
49579 'emailMask' : /[a-z0-9_\.\-@]/i,
49582 * The function used to validate URLs
49583 * @param {String} value The URL
49585 'url' : function(v){
49586 return url.test(v);
49589 * The error text to display when the url validation function returns false
49592 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
49595 * The function used to validate alpha values
49596 * @param {String} value The value
49598 'alpha' : function(v){
49599 return alpha.test(v);
49602 * The error text to display when the alpha validation function returns false
49605 'alphaText' : 'This field should only contain letters and _',
49607 * The keystroke filter mask to be applied on alpha input
49610 'alphaMask' : /[a-z_]/i,
49613 * The function used to validate alphanumeric values
49614 * @param {String} value The value
49616 'alphanum' : function(v){
49617 return alphanum.test(v);
49620 * The error text to display when the alphanumeric validation function returns false
49623 'alphanumText' : 'This field should only contain letters, numbers and _',
49625 * The keystroke filter mask to be applied on alphanumeric input
49628 'alphanumMask' : /[a-z0-9_]/i
49630 }();//<script type="text/javascript">
49633 * @class Roo.form.FCKeditor
49634 * @extends Roo.form.TextArea
49635 * Wrapper around the FCKEditor http://www.fckeditor.net
49637 * Creates a new FCKeditor
49638 * @param {Object} config Configuration options
49640 Roo.form.FCKeditor = function(config){
49641 Roo.form.FCKeditor.superclass.constructor.call(this, config);
49644 * @event editorinit
49645 * Fired when the editor is initialized - you can add extra handlers here..
49646 * @param {FCKeditor} this
49647 * @param {Object} the FCK object.
49654 Roo.form.FCKeditor.editors = { };
49655 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
49657 //defaultAutoCreate : {
49658 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
49662 * @cfg {Object} fck options - see fck manual for details.
49667 * @cfg {Object} fck toolbar set (Basic or Default)
49669 toolbarSet : 'Basic',
49671 * @cfg {Object} fck BasePath
49673 basePath : '/fckeditor/',
49681 onRender : function(ct, position)
49684 this.defaultAutoCreate = {
49686 style:"width:300px;height:60px;",
49687 autocomplete: "new-password"
49690 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
49693 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
49694 if(this.preventScrollbars){
49695 this.el.setStyle("overflow", "hidden");
49697 this.el.setHeight(this.growMin);
49700 //console.log('onrender' + this.getId() );
49701 Roo.form.FCKeditor.editors[this.getId()] = this;
49704 this.replaceTextarea() ;
49708 getEditor : function() {
49709 return this.fckEditor;
49712 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
49713 * @param {Mixed} value The value to set
49717 setValue : function(value)
49719 //console.log('setValue: ' + value);
49721 if(typeof(value) == 'undefined') { // not sure why this is happending...
49724 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
49726 //if(!this.el || !this.getEditor()) {
49727 // this.value = value;
49728 //this.setValue.defer(100,this,[value]);
49732 if(!this.getEditor()) {
49736 this.getEditor().SetData(value);
49743 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
49744 * @return {Mixed} value The field value
49746 getValue : function()
49749 if (this.frame && this.frame.dom.style.display == 'none') {
49750 return Roo.form.FCKeditor.superclass.getValue.call(this);
49753 if(!this.el || !this.getEditor()) {
49755 // this.getValue.defer(100,this);
49760 var value=this.getEditor().GetData();
49761 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
49762 return Roo.form.FCKeditor.superclass.getValue.call(this);
49768 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
49769 * @return {Mixed} value The field value
49771 getRawValue : function()
49773 if (this.frame && this.frame.dom.style.display == 'none') {
49774 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
49777 if(!this.el || !this.getEditor()) {
49778 //this.getRawValue.defer(100,this);
49785 var value=this.getEditor().GetData();
49786 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
49787 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
49791 setSize : function(w,h) {
49795 //if (this.frame && this.frame.dom.style.display == 'none') {
49796 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
49799 //if(!this.el || !this.getEditor()) {
49800 // this.setSize.defer(100,this, [w,h]);
49806 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
49808 this.frame.dom.setAttribute('width', w);
49809 this.frame.dom.setAttribute('height', h);
49810 this.frame.setSize(w,h);
49814 toggleSourceEdit : function(value) {
49818 this.el.dom.style.display = value ? '' : 'none';
49819 this.frame.dom.style.display = value ? 'none' : '';
49824 focus: function(tag)
49826 if (this.frame.dom.style.display == 'none') {
49827 return Roo.form.FCKeditor.superclass.focus.call(this);
49829 if(!this.el || !this.getEditor()) {
49830 this.focus.defer(100,this, [tag]);
49837 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
49838 this.getEditor().Focus();
49840 if (!this.getEditor().Selection.GetSelection()) {
49841 this.focus.defer(100,this, [tag]);
49846 var r = this.getEditor().EditorDocument.createRange();
49847 r.setStart(tgs[0],0);
49848 r.setEnd(tgs[0],0);
49849 this.getEditor().Selection.GetSelection().removeAllRanges();
49850 this.getEditor().Selection.GetSelection().addRange(r);
49851 this.getEditor().Focus();
49858 replaceTextarea : function()
49860 if ( document.getElementById( this.getId() + '___Frame' ) ) {
49863 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
49865 // We must check the elements firstly using the Id and then the name.
49866 var oTextarea = document.getElementById( this.getId() );
49868 var colElementsByName = document.getElementsByName( this.getId() ) ;
49870 oTextarea.style.display = 'none' ;
49872 if ( oTextarea.tabIndex ) {
49873 this.TabIndex = oTextarea.tabIndex ;
49876 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
49877 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
49878 this.frame = Roo.get(this.getId() + '___Frame')
49881 _getConfigHtml : function()
49885 for ( var o in this.fckconfig ) {
49886 sConfig += sConfig.length > 0 ? '&' : '';
49887 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
49890 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
49894 _getIFrameHtml : function()
49896 var sFile = 'fckeditor.html' ;
49897 /* no idea what this is about..
49900 if ( (/fcksource=true/i).test( window.top.location.search ) )
49901 sFile = 'fckeditor.original.html' ;
49906 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
49907 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
49910 var html = '<iframe id="' + this.getId() +
49911 '___Frame" src="' + sLink +
49912 '" width="' + this.width +
49913 '" height="' + this.height + '"' +
49914 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
49915 ' frameborder="0" scrolling="no"></iframe>' ;
49920 _insertHtmlBefore : function( html, element )
49922 if ( element.insertAdjacentHTML ) {
49924 element.insertAdjacentHTML( 'beforeBegin', html ) ;
49926 var oRange = document.createRange() ;
49927 oRange.setStartBefore( element ) ;
49928 var oFragment = oRange.createContextualFragment( html );
49929 element.parentNode.insertBefore( oFragment, element ) ;
49942 //Roo.reg('fckeditor', Roo.form.FCKeditor);
49944 function FCKeditor_OnComplete(editorInstance){
49945 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
49946 f.fckEditor = editorInstance;
49947 //console.log("loaded");
49948 f.fireEvent('editorinit', f, editorInstance);
49968 //<script type="text/javascript">
49970 * @class Roo.form.GridField
49971 * @extends Roo.form.Field
49972 * Embed a grid (or editable grid into a form)
49975 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
49977 * xgrid.store = Roo.data.Store
49978 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
49979 * xgrid.store.reader = Roo.data.JsonReader
49983 * Creates a new GridField
49984 * @param {Object} config Configuration options
49986 Roo.form.GridField = function(config){
49987 Roo.form.GridField.superclass.constructor.call(this, config);
49991 Roo.extend(Roo.form.GridField, Roo.form.Field, {
49993 * @cfg {Number} width - used to restrict width of grid..
49997 * @cfg {Number} height - used to restrict height of grid..
50001 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
50007 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
50008 * {tag: "input", type: "checkbox", autocomplete: "off"})
50010 // defaultAutoCreate : { tag: 'div' },
50011 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'new-password'},
50013 * @cfg {String} addTitle Text to include for adding a title.
50017 onResize : function(){
50018 Roo.form.Field.superclass.onResize.apply(this, arguments);
50021 initEvents : function(){
50022 // Roo.form.Checkbox.superclass.initEvents.call(this);
50023 // has no events...
50028 getResizeEl : function(){
50032 getPositionEl : function(){
50037 onRender : function(ct, position){
50039 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
50040 var style = this.style;
50043 Roo.form.GridField.superclass.onRender.call(this, ct, position);
50044 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
50045 this.viewEl = this.wrap.createChild({ tag: 'div' });
50047 this.viewEl.applyStyles(style);
50050 this.viewEl.setWidth(this.width);
50053 this.viewEl.setHeight(this.height);
50055 //if(this.inputValue !== undefined){
50056 //this.setValue(this.value);
50059 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
50062 this.grid.render();
50063 this.grid.getDataSource().on('remove', this.refreshValue, this);
50064 this.grid.getDataSource().on('update', this.refreshValue, this);
50065 this.grid.on('afteredit', this.refreshValue, this);
50071 * Sets the value of the item.
50072 * @param {String} either an object or a string..
50074 setValue : function(v){
50076 v = v || []; // empty set..
50077 // this does not seem smart - it really only affects memoryproxy grids..
50078 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
50079 var ds = this.grid.getDataSource();
50080 // assumes a json reader..
50082 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
50083 ds.loadData( data);
50085 // clear selection so it does not get stale.
50086 if (this.grid.sm) {
50087 this.grid.sm.clearSelections();
50090 Roo.form.GridField.superclass.setValue.call(this, v);
50091 this.refreshValue();
50092 // should load data in the grid really....
50096 refreshValue: function() {
50098 this.grid.getDataSource().each(function(r) {
50101 this.el.dom.value = Roo.encode(val);
50109 * Ext JS Library 1.1.1
50110 * Copyright(c) 2006-2007, Ext JS, LLC.
50112 * Originally Released Under LGPL - original licence link has changed is not relivant.
50115 * <script type="text/javascript">
50118 * @class Roo.form.DisplayField
50119 * @extends Roo.form.Field
50120 * A generic Field to display non-editable data.
50121 * @cfg {Boolean} closable (true|false) default false
50123 * Creates a new Display Field item.
50124 * @param {Object} config Configuration options
50126 Roo.form.DisplayField = function(config){
50127 Roo.form.DisplayField.superclass.constructor.call(this, config);
50132 * Fires after the click the close btn
50133 * @param {Roo.form.DisplayField} this
50139 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
50140 inputType: 'hidden',
50146 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
50148 focusClass : undefined,
50150 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
50152 fieldClass: 'x-form-field',
50155 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
50157 valueRenderer: undefined,
50161 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
50162 * {tag: "input", type: "checkbox", autocomplete: "off"})
50165 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
50169 onResize : function(){
50170 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
50174 initEvents : function(){
50175 // Roo.form.Checkbox.superclass.initEvents.call(this);
50176 // has no events...
50179 this.closeEl.on('click', this.onClose, this);
50185 getResizeEl : function(){
50189 getPositionEl : function(){
50194 onRender : function(ct, position){
50196 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
50197 //if(this.inputValue !== undefined){
50198 this.wrap = this.el.wrap();
50200 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
50203 this.closeEl = this.wrap.createChild({ tag: 'div', cls: 'x-dlg-close'});
50206 if (this.bodyStyle) {
50207 this.viewEl.applyStyles(this.bodyStyle);
50209 //this.viewEl.setStyle('padding', '2px');
50211 this.setValue(this.value);
50216 initValue : Roo.emptyFn,
50221 onClick : function(){
50226 * Sets the checked state of the checkbox.
50227 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
50229 setValue : function(v){
50231 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
50232 // this might be called before we have a dom element..
50233 if (!this.viewEl) {
50236 this.viewEl.dom.innerHTML = html;
50237 Roo.form.DisplayField.superclass.setValue.call(this, v);
50241 onClose : function(e)
50243 e.preventDefault();
50245 this.fireEvent('close', this);
50254 * @class Roo.form.DayPicker
50255 * @extends Roo.form.Field
50256 * A Day picker show [M] [T] [W] ....
50258 * Creates a new Day Picker
50259 * @param {Object} config Configuration options
50261 Roo.form.DayPicker= function(config){
50262 Roo.form.DayPicker.superclass.constructor.call(this, config);
50266 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
50268 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
50270 focusClass : undefined,
50272 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
50274 fieldClass: "x-form-field",
50277 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
50278 * {tag: "input", type: "checkbox", autocomplete: "off"})
50280 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "new-password"},
50283 actionMode : 'viewEl',
50287 inputType : 'hidden',
50290 inputElement: false, // real input element?
50291 basedOn: false, // ????
50293 isFormField: true, // not sure where this is needed!!!!
50295 onResize : function(){
50296 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
50297 if(!this.boxLabel){
50298 this.el.alignTo(this.wrap, 'c-c');
50302 initEvents : function(){
50303 Roo.form.Checkbox.superclass.initEvents.call(this);
50304 this.el.on("click", this.onClick, this);
50305 this.el.on("change", this.onClick, this);
50309 getResizeEl : function(){
50313 getPositionEl : function(){
50319 onRender : function(ct, position){
50320 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
50322 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
50324 var r1 = '<table><tr>';
50325 var r2 = '<tr class="x-form-daypick-icons">';
50326 for (var i=0; i < 7; i++) {
50327 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
50328 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
50331 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
50332 viewEl.select('img').on('click', this.onClick, this);
50333 this.viewEl = viewEl;
50336 // this will not work on Chrome!!!
50337 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
50338 this.el.on('propertychange', this.setFromHidden, this); //ie
50346 initValue : Roo.emptyFn,
50349 * Returns the checked state of the checkbox.
50350 * @return {Boolean} True if checked, else false
50352 getValue : function(){
50353 return this.el.dom.value;
50358 onClick : function(e){
50359 //this.setChecked(!this.checked);
50360 Roo.get(e.target).toggleClass('x-menu-item-checked');
50361 this.refreshValue();
50362 //if(this.el.dom.checked != this.checked){
50363 // this.setValue(this.el.dom.checked);
50368 refreshValue : function()
50371 this.viewEl.select('img',true).each(function(e,i,n) {
50372 val += e.is(".x-menu-item-checked") ? String(n) : '';
50374 this.setValue(val, true);
50378 * Sets the checked state of the checkbox.
50379 * On is always based on a string comparison between inputValue and the param.
50380 * @param {Boolean/String} value - the value to set
50381 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
50383 setValue : function(v,suppressEvent){
50384 if (!this.el.dom) {
50387 var old = this.el.dom.value ;
50388 this.el.dom.value = v;
50389 if (suppressEvent) {
50393 // update display..
50394 this.viewEl.select('img',true).each(function(e,i,n) {
50396 var on = e.is(".x-menu-item-checked");
50397 var newv = v.indexOf(String(n)) > -1;
50399 e.toggleClass('x-menu-item-checked');
50405 this.fireEvent('change', this, v, old);
50410 // handle setting of hidden value by some other method!!?!?
50411 setFromHidden: function()
50416 //console.log("SET FROM HIDDEN");
50417 //alert('setFrom hidden');
50418 this.setValue(this.el.dom.value);
50421 onDestroy : function()
50424 Roo.get(this.viewEl).remove();
50427 Roo.form.DayPicker.superclass.onDestroy.call(this);
50431 * RooJS Library 1.1.1
50432 * Copyright(c) 2008-2011 Alan Knowles
50439 * @class Roo.form.ComboCheck
50440 * @extends Roo.form.ComboBox
50441 * A combobox for multiple select items.
50443 * FIXME - could do with a reset button..
50446 * Create a new ComboCheck
50447 * @param {Object} config Configuration options
50449 Roo.form.ComboCheck = function(config){
50450 Roo.form.ComboCheck.superclass.constructor.call(this, config);
50451 // should verify some data...
50453 // hiddenName = required..
50454 // displayField = required
50455 // valudField == required
50456 var req= [ 'hiddenName', 'displayField', 'valueField' ];
50458 Roo.each(req, function(e) {
50459 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
50460 throw "Roo.form.ComboCheck : missing value for: " + e;
50467 Roo.extend(Roo.form.ComboCheck, Roo.form.ComboBox, {
50472 selectedClass: 'x-menu-item-checked',
50475 onRender : function(ct, position){
50481 var cls = 'x-combo-list';
50484 this.tpl = new Roo.Template({
50485 html : '<div class="'+cls+'-item x-menu-check-item">' +
50486 '<img class="x-menu-item-icon" style="margin: 0px;" src="' + Roo.BLANK_IMAGE_URL + '">' +
50487 '<span>{' + this.displayField + '}</span>' +
50494 Roo.form.ComboCheck.superclass.onRender.call(this, ct, position);
50495 this.view.singleSelect = false;
50496 this.view.multiSelect = true;
50497 this.view.toggleSelect = true;
50498 this.pageTb.add(new Roo.Toolbar.Fill(), {
50501 handler: function()
50508 onViewOver : function(e, t){
50514 onViewClick : function(doFocus,index){
50518 select: function () {
50519 //Roo.log("SELECT CALLED");
50522 selectByValue : function(xv, scrollIntoView){
50523 var ar = this.getValueArray();
50526 Roo.each(ar, function(v) {
50527 if(v === undefined || v === null){
50530 var r = this.findRecord(this.valueField, v);
50532 sels.push(this.store.indexOf(r))
50536 this.view.select(sels);
50542 onSelect : function(record, index){
50543 // Roo.log("onselect Called");
50544 // this is only called by the clear button now..
50545 this.view.clearSelections();
50546 this.setValue('[]');
50547 if (this.value != this.valueBefore) {
50548 this.fireEvent('change', this, this.value, this.valueBefore);
50549 this.valueBefore = this.value;
50552 getValueArray : function()
50557 //Roo.log(this.value);
50558 if (typeof(this.value) == 'undefined') {
50561 var ar = Roo.decode(this.value);
50562 return ar instanceof Array ? ar : []; //?? valid?
50565 Roo.log(e + "\nRoo.form.ComboCheck:getValueArray invalid data:" + this.getValue());
50570 expand : function ()
50573 Roo.form.ComboCheck.superclass.expand.call(this);
50574 this.valueBefore = typeof(this.value) == 'undefined' ? '' : this.value;
50575 //this.valueBefore = typeof(this.valueBefore) == 'undefined' ? '' : this.valueBefore;
50580 collapse : function(){
50581 Roo.form.ComboCheck.superclass.collapse.call(this);
50582 var sl = this.view.getSelectedIndexes();
50583 var st = this.store;
50587 Roo.each(sl, function(i) {
50589 nv.push(r.get(this.valueField));
50591 this.setValue(Roo.encode(nv));
50592 if (this.value != this.valueBefore) {
50594 this.fireEvent('change', this, this.value, this.valueBefore);
50595 this.valueBefore = this.value;
50600 setValue : function(v){
50604 var vals = this.getValueArray();
50606 Roo.each(vals, function(k) {
50607 var r = this.findRecord(this.valueField, k);
50609 tv.push(r.data[this.displayField]);
50610 }else if(this.valueNotFoundText !== undefined){
50611 tv.push( this.valueNotFoundText );
50616 Roo.form.ComboBox.superclass.setValue.call(this, tv.join(', '));
50617 this.hiddenField.value = v;
50623 * Ext JS Library 1.1.1
50624 * Copyright(c) 2006-2007, Ext JS, LLC.
50626 * Originally Released Under LGPL - original licence link has changed is not relivant.
50629 * <script type="text/javascript">
50633 * @class Roo.form.Signature
50634 * @extends Roo.form.Field
50638 * @param {Object} config Configuration options
50641 Roo.form.Signature = function(config){
50642 Roo.form.Signature.superclass.constructor.call(this, config);
50644 this.addEvents({// not in used??
50647 * Fires when the 'confirm' icon is pressed (add a listener to enable add button)
50648 * @param {Roo.form.Signature} combo This combo box
50653 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
50654 * @param {Roo.form.ComboBox} combo This combo box
50655 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
50661 Roo.extend(Roo.form.Signature, Roo.form.Field, {
50663 * @cfg {Object} labels Label to use when rendering a form.
50667 * confirm : "Confirm"
50672 confirm : "Confirm"
50675 * @cfg {Number} width The signature panel width (defaults to 300)
50679 * @cfg {Number} height The signature panel height (defaults to 100)
50683 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to false)
50685 allowBlank : false,
50688 // {Object} signPanel The signature SVG panel element (defaults to {})
50690 // {Boolean} isMouseDown False to validate that the mouse down event (defaults to false)
50691 isMouseDown : false,
50692 // {Boolean} isConfirmed validate the signature is confirmed or not for submitting form (defaults to false)
50693 isConfirmed : false,
50694 // {String} signatureTmp SVG mapping string (defaults to empty string)
50698 defaultAutoCreate : { // modified by initCompnoent..
50704 onRender : function(ct, position){
50706 Roo.form.Signature.superclass.onRender.call(this, ct, position);
50708 this.wrap = this.el.wrap({
50709 cls:'x-form-signature-wrap', style : 'width: ' + this.width + 'px', cn:{cls:'x-form-signature'}
50712 this.createToolbar(this);
50713 this.signPanel = this.wrap.createChild({
50715 style: 'width: ' + this.width + 'px; height: ' + this.height + 'px; border: 0;'
50719 this.svgID = Roo.id();
50720 this.svgEl = this.signPanel.createChild({
50721 xmlns : 'http://www.w3.org/2000/svg',
50723 id : this.svgID + "-svg",
50725 height: this.height,
50726 viewBox: '0 0 '+this.width+' '+this.height,
50730 id: this.svgID + "-svg-r",
50732 height: this.height,
50737 id: this.svgID + "-svg-l",
50739 y1: (this.height*0.8), // start set the line in 80% of height
50740 x2: this.width, // end
50741 y2: (this.height*0.8), // end set the line in 80% of height
50743 'stroke-width': "1",
50744 'stroke-dasharray': "3",
50745 'shape-rendering': "crispEdges",
50746 'pointer-events': "none"
50750 id: this.svgID + "-svg-p",
50752 'stroke-width': "3",
50754 'pointer-events': 'none'
50759 this.svgBox = this.svgEl.dom.getScreenCTM();
50761 createSVG : function(){
50762 var svg = this.signPanel;
50763 var r = svg.select('#'+ this.svgID + '-svg-r', true).first().dom;
50766 r.addEventListener('mousedown', function(e) { return t.down(e); }, false);
50767 r.addEventListener('mousemove', function(e) { return t.move(e); }, false);
50768 r.addEventListener('mouseup', function(e) { return t.up(e); }, false);
50769 r.addEventListener('mouseout', function(e) { return t.up(e); }, false);
50770 r.addEventListener('touchstart', function(e) { return t.down(e); }, false);
50771 r.addEventListener('touchmove', function(e) { return t.move(e); }, false);
50772 r.addEventListener('touchend', function(e) { return t.up(e); }, false);
50775 isTouchEvent : function(e){
50776 return e.type.match(/^touch/);
50778 getCoords : function (e) {
50779 var pt = this.svgEl.dom.createSVGPoint();
50782 if (this.isTouchEvent(e)) {
50783 pt.x = e.targetTouches[0].clientX;
50784 pt.y = e.targetTouches[0].clientY;
50786 var a = this.svgEl.dom.getScreenCTM();
50787 var b = a.inverse();
50788 var mx = pt.matrixTransform(b);
50789 return mx.x + ',' + mx.y;
50791 //mouse event headler
50792 down : function (e) {
50793 this.signatureTmp += 'M' + this.getCoords(e) + ' ';
50794 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr('d', this.signatureTmp);
50796 this.isMouseDown = true;
50798 e.preventDefault();
50800 move : function (e) {
50801 if (this.isMouseDown) {
50802 this.signatureTmp += 'L' + this.getCoords(e) + ' ';
50803 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', this.signatureTmp);
50806 e.preventDefault();
50808 up : function (e) {
50809 this.isMouseDown = false;
50810 var sp = this.signatureTmp.split(' ');
50813 if(!sp[sp.length-2].match(/^L/)){
50817 this.signatureTmp = sp.join(" ");
50820 if(this.getValue() != this.signatureTmp){
50821 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
50822 this.isConfirmed = false;
50824 e.preventDefault();
50828 * Protected method that will not generally be called directly. It
50829 * is called when the editor creates its toolbar. Override this method if you need to
50830 * add custom toolbar buttons.
50831 * @param {HtmlEditor} editor
50833 createToolbar : function(editor){
50834 function btn(id, toggle, handler){
50835 var xid = fid + '-'+ id ;
50839 cls : 'x-btn-icon x-edit-'+id,
50840 enableToggle:toggle !== false,
50841 scope: editor, // was editor...
50842 handler:handler||editor.relayBtnCmd,
50843 clickEvent:'mousedown',
50844 tooltip: etb.buttonTips[id] || undefined, ///tips ???
50850 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
50854 cls : ' x-signature-btn x-signature-'+id,
50855 scope: editor, // was editor...
50856 handler: this.reset,
50857 clickEvent:'mousedown',
50858 text: this.labels.clear
50865 cls : ' x-signature-btn x-signature-'+id,
50866 scope: editor, // was editor...
50867 handler: this.confirmHandler,
50868 clickEvent:'mousedown',
50869 text: this.labels.confirm
50876 * when user is clicked confirm then show this image.....
50878 * @return {String} Image Data URI
50880 getImageDataURI : function(){
50881 var svg = this.svgEl.dom.parentNode.innerHTML;
50882 var src = 'data:image/svg+xml;base64,'+window.btoa(svg);
50887 * @return {Boolean} this.isConfirmed
50889 getConfirmed : function(){
50890 return this.isConfirmed;
50894 * @return {Number} this.width
50896 getWidth : function(){
50901 * @return {Number} this.height
50903 getHeight : function(){
50904 return this.height;
50907 getSignature : function(){
50908 return this.signatureTmp;
50911 reset : function(){
50912 this.signatureTmp = '';
50913 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
50914 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', '');
50915 this.isConfirmed = false;
50916 Roo.form.Signature.superclass.reset.call(this);
50918 setSignature : function(s){
50919 this.signatureTmp = s;
50920 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
50921 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', s);
50923 this.isConfirmed = false;
50924 Roo.form.Signature.superclass.reset.call(this);
50927 // Roo.log(this.signPanel.dom.contentWindow.up())
50930 setConfirmed : function(){
50934 // Roo.log(Roo.get(this.signPanel.dom.contentWindow.r).attr('fill', '#cfc'));
50937 confirmHandler : function(){
50938 if(!this.getSignature()){
50942 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#cfc');
50943 this.setValue(this.getSignature());
50944 this.isConfirmed = true;
50946 this.fireEvent('confirm', this);
50949 // Subclasses should provide the validation implementation by overriding this
50950 validateValue : function(value){
50951 if(this.allowBlank){
50955 if(this.isConfirmed){
50962 * Ext JS Library 1.1.1
50963 * Copyright(c) 2006-2007, Ext JS, LLC.
50965 * Originally Released Under LGPL - original licence link has changed is not relivant.
50968 * <script type="text/javascript">
50973 * @class Roo.form.ComboBox
50974 * @extends Roo.form.TriggerField
50975 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
50977 * Create a new ComboBox.
50978 * @param {Object} config Configuration options
50980 Roo.form.Select = function(config){
50981 Roo.form.Select.superclass.constructor.call(this, config);
50985 Roo.extend(Roo.form.Select , Roo.form.ComboBox, {
50987 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
50990 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
50991 * rendering into an Roo.Editor, defaults to false)
50994 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
50995 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
50998 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
51001 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
51002 * the dropdown list (defaults to undefined, with no header element)
51006 * @cfg {String/Roo.Template} tpl The template to use to render the output
51010 defaultAutoCreate : {tag: "select" },
51012 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
51014 listWidth: undefined,
51016 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
51017 * mode = 'remote' or 'text' if mode = 'local')
51019 displayField: undefined,
51021 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
51022 * mode = 'remote' or 'value' if mode = 'local').
51023 * Note: use of a valueField requires the user make a selection
51024 * in order for a value to be mapped.
51026 valueField: undefined,
51030 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
51031 * field's data value (defaults to the underlying DOM element's name)
51033 hiddenName: undefined,
51035 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
51039 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
51041 selectedClass: 'x-combo-selected',
51043 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
51044 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
51045 * which displays a downward arrow icon).
51047 triggerClass : 'x-form-arrow-trigger',
51049 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
51053 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
51054 * anchor positions (defaults to 'tl-bl')
51056 listAlign: 'tl-bl?',
51058 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
51062 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
51063 * query specified by the allQuery config option (defaults to 'query')
51065 triggerAction: 'query',
51067 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
51068 * (defaults to 4, does not apply if editable = false)
51072 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
51073 * delay (typeAheadDelay) if it matches a known value (defaults to false)
51077 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
51078 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
51082 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
51083 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
51087 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
51088 * when editable = true (defaults to false)
51090 selectOnFocus:false,
51092 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
51094 queryParam: 'query',
51096 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
51097 * when mode = 'remote' (defaults to 'Loading...')
51099 loadingText: 'Loading...',
51101 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
51105 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
51109 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
51110 * traditional select (defaults to true)
51114 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
51118 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
51122 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
51123 * listWidth has a higher value)
51127 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
51128 * allow the user to set arbitrary text into the field (defaults to false)
51130 forceSelection:false,
51132 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
51133 * if typeAhead = true (defaults to 250)
51135 typeAheadDelay : 250,
51137 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
51138 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
51140 valueNotFoundText : undefined,
51143 * @cfg {String} defaultValue The value displayed after loading the store.
51148 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
51150 blockFocus : false,
51153 * @cfg {Boolean} disableClear Disable showing of clear button.
51155 disableClear : false,
51157 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
51159 alwaysQuery : false,
51165 // element that contains real text value.. (when hidden is used..)
51168 onRender : function(ct, position){
51169 Roo.form.Field.prototype.onRender.call(this, ct, position);
51172 this.store.on('beforeload', this.onBeforeLoad, this);
51173 this.store.on('load', this.onLoad, this);
51174 this.store.on('loadexception', this.onLoadException, this);
51175 this.store.load({});
51183 initEvents : function(){
51184 //Roo.form.ComboBox.superclass.initEvents.call(this);
51188 onDestroy : function(){
51191 this.store.un('beforeload', this.onBeforeLoad, this);
51192 this.store.un('load', this.onLoad, this);
51193 this.store.un('loadexception', this.onLoadException, this);
51195 //Roo.form.ComboBox.superclass.onDestroy.call(this);
51199 fireKey : function(e){
51200 if(e.isNavKeyPress() && !this.list.isVisible()){
51201 this.fireEvent("specialkey", this, e);
51206 onResize: function(w, h){
51214 * Allow or prevent the user from directly editing the field text. If false is passed,
51215 * the user will only be able to select from the items defined in the dropdown list. This method
51216 * is the runtime equivalent of setting the 'editable' config option at config time.
51217 * @param {Boolean} value True to allow the user to directly edit the field text
51219 setEditable : function(value){
51224 onBeforeLoad : function(){
51226 Roo.log("Select before load");
51229 this.innerList.update(this.loadingText ?
51230 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
51231 //this.restrictHeight();
51232 this.selectedIndex = -1;
51236 onLoad : function(){
51239 var dom = this.el.dom;
51240 dom.innerHTML = '';
51241 var od = dom.ownerDocument;
51243 if (this.emptyText) {
51244 var op = od.createElement('option');
51245 op.setAttribute('value', '');
51246 op.innerHTML = String.format('{0}', this.emptyText);
51247 dom.appendChild(op);
51249 if(this.store.getCount() > 0){
51251 var vf = this.valueField;
51252 var df = this.displayField;
51253 this.store.data.each(function(r) {
51254 // which colmsn to use... testing - cdoe / title..
51255 var op = od.createElement('option');
51256 op.setAttribute('value', r.data[vf]);
51257 op.innerHTML = String.format('{0}', r.data[df]);
51258 dom.appendChild(op);
51260 if (typeof(this.defaultValue != 'undefined')) {
51261 this.setValue(this.defaultValue);
51266 //this.onEmptyResults();
51271 onLoadException : function()
51273 dom.innerHTML = '';
51275 Roo.log("Select on load exception");
51279 Roo.log(this.store.reader.jsonData);
51280 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
51281 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
51287 onTypeAhead : function(){
51292 onSelect : function(record, index){
51293 Roo.log('on select?');
51295 if(this.fireEvent('beforeselect', this, record, index) !== false){
51296 this.setFromData(index > -1 ? record.data : false);
51298 this.fireEvent('select', this, record, index);
51303 * Returns the currently selected field value or empty string if no value is set.
51304 * @return {String} value The selected value
51306 getValue : function(){
51307 var dom = this.el.dom;
51308 this.value = dom.options[dom.selectedIndex].value;
51314 * Clears any text/value currently set in the field
51316 clearValue : function(){
51318 this.el.dom.selectedIndex = this.emptyText ? 0 : -1;
51323 * Sets the specified value into the field. If the value finds a match, the corresponding record text
51324 * will be displayed in the field. If the value does not match the data value of an existing item,
51325 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
51326 * Otherwise the field will be blank (although the value will still be set).
51327 * @param {String} value The value to match
51329 setValue : function(v){
51330 var d = this.el.dom;
51331 for (var i =0; i < d.options.length;i++) {
51332 if (v == d.options[i].value) {
51333 d.selectedIndex = i;
51341 * @property {Object} the last set data for the element
51346 * Sets the value of the field based on a object which is related to the record format for the store.
51347 * @param {Object} value the value to set as. or false on reset?
51349 setFromData : function(o){
51350 Roo.log('setfrom data?');
51356 reset : function(){
51360 findRecord : function(prop, value){
51365 if(this.store.getCount() > 0){
51366 this.store.each(function(r){
51367 if(r.data[prop] == value){
51377 getName: function()
51379 // returns hidden if it's set..
51380 if (!this.rendered) {return ''};
51381 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
51389 onEmptyResults : function(){
51390 Roo.log('empty results');
51395 * Returns true if the dropdown list is expanded, else false.
51397 isExpanded : function(){
51402 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
51403 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
51404 * @param {String} value The data value of the item to select
51405 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
51406 * selected item if it is not currently in view (defaults to true)
51407 * @return {Boolean} True if the value matched an item in the list, else false
51409 selectByValue : function(v, scrollIntoView){
51410 Roo.log('select By Value');
51413 if(v !== undefined && v !== null){
51414 var r = this.findRecord(this.valueField || this.displayField, v);
51416 this.select(this.store.indexOf(r), scrollIntoView);
51424 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
51425 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
51426 * @param {Number} index The zero-based index of the list item to select
51427 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
51428 * selected item if it is not currently in view (defaults to true)
51430 select : function(index, scrollIntoView){
51431 Roo.log('select ');
51434 this.selectedIndex = index;
51435 this.view.select(index);
51436 if(scrollIntoView !== false){
51437 var el = this.view.getNode(index);
51439 this.innerList.scrollChildIntoView(el, false);
51447 validateBlur : function(){
51454 initQuery : function(){
51455 this.doQuery(this.getRawValue());
51459 doForce : function(){
51460 if(this.el.dom.value.length > 0){
51461 this.el.dom.value =
51462 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
51468 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
51469 * query allowing the query action to be canceled if needed.
51470 * @param {String} query The SQL query to execute
51471 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
51472 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
51473 * saved in the current store (defaults to false)
51475 doQuery : function(q, forceAll){
51477 Roo.log('doQuery?');
51478 if(q === undefined || q === null){
51483 forceAll: forceAll,
51487 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
51491 forceAll = qe.forceAll;
51492 if(forceAll === true || (q.length >= this.minChars)){
51493 if(this.lastQuery != q || this.alwaysQuery){
51494 this.lastQuery = q;
51495 if(this.mode == 'local'){
51496 this.selectedIndex = -1;
51498 this.store.clearFilter();
51500 this.store.filter(this.displayField, q);
51504 this.store.baseParams[this.queryParam] = q;
51506 params: this.getParams(q)
51511 this.selectedIndex = -1;
51518 getParams : function(q){
51520 //p[this.queryParam] = q;
51523 p.limit = this.pageSize;
51529 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
51531 collapse : function(){
51536 collapseIf : function(e){
51541 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
51543 expand : function(){
51551 * @cfg {Boolean} grow
51555 * @cfg {Number} growMin
51559 * @cfg {Number} growMax
51567 setWidth : function()
51571 getResizeEl : function(){
51574 });//<script type="text/javasscript">
51578 * @class Roo.DDView
51579 * A DnD enabled version of Roo.View.
51580 * @param {Element/String} container The Element in which to create the View.
51581 * @param {String} tpl The template string used to create the markup for each element of the View
51582 * @param {Object} config The configuration properties. These include all the config options of
51583 * {@link Roo.View} plus some specific to this class.<br>
51585 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
51586 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
51588 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
51589 .x-view-drag-insert-above {
51590 border-top:1px dotted #3366cc;
51592 .x-view-drag-insert-below {
51593 border-bottom:1px dotted #3366cc;
51599 Roo.DDView = function(container, tpl, config) {
51600 Roo.DDView.superclass.constructor.apply(this, arguments);
51601 this.getEl().setStyle("outline", "0px none");
51602 this.getEl().unselectable();
51603 if (this.dragGroup) {
51604 this.setDraggable(this.dragGroup.split(","));
51606 if (this.dropGroup) {
51607 this.setDroppable(this.dropGroup.split(","));
51609 if (this.deletable) {
51610 this.setDeletable();
51612 this.isDirtyFlag = false;
51618 Roo.extend(Roo.DDView, Roo.View, {
51619 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
51620 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
51621 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
51622 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
51626 reset: Roo.emptyFn,
51628 clearInvalid: Roo.form.Field.prototype.clearInvalid,
51630 validate: function() {
51634 destroy: function() {
51635 this.purgeListeners();
51636 this.getEl.removeAllListeners();
51637 this.getEl().remove();
51638 if (this.dragZone) {
51639 if (this.dragZone.destroy) {
51640 this.dragZone.destroy();
51643 if (this.dropZone) {
51644 if (this.dropZone.destroy) {
51645 this.dropZone.destroy();
51650 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
51651 getName: function() {
51655 /** Loads the View from a JSON string representing the Records to put into the Store. */
51656 setValue: function(v) {
51658 throw "DDView.setValue(). DDView must be constructed with a valid Store";
51661 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
51662 this.store.proxy = new Roo.data.MemoryProxy(data);
51666 /** @return {String} a parenthesised list of the ids of the Records in the View. */
51667 getValue: function() {
51669 this.store.each(function(rec) {
51670 result += rec.id + ',';
51672 return result.substr(0, result.length - 1) + ')';
51675 getIds: function() {
51676 var i = 0, result = new Array(this.store.getCount());
51677 this.store.each(function(rec) {
51678 result[i++] = rec.id;
51683 isDirty: function() {
51684 return this.isDirtyFlag;
51688 * Part of the Roo.dd.DropZone interface. If no target node is found, the
51689 * whole Element becomes the target, and this causes the drop gesture to append.
51691 getTargetFromEvent : function(e) {
51692 var target = e.getTarget();
51693 while ((target !== null) && (target.parentNode != this.el.dom)) {
51694 target = target.parentNode;
51697 target = this.el.dom.lastChild || this.el.dom;
51703 * Create the drag data which consists of an object which has the property "ddel" as
51704 * the drag proxy element.
51706 getDragData : function(e) {
51707 var target = this.findItemFromChild(e.getTarget());
51709 this.handleSelection(e);
51710 var selNodes = this.getSelectedNodes();
51713 copy: this.copy || (this.allowCopy && e.ctrlKey),
51717 var selectedIndices = this.getSelectedIndexes();
51718 for (var i = 0; i < selectedIndices.length; i++) {
51719 dragData.records.push(this.store.getAt(selectedIndices[i]));
51721 if (selNodes.length == 1) {
51722 dragData.ddel = target.cloneNode(true); // the div element
51724 var div = document.createElement('div'); // create the multi element drag "ghost"
51725 div.className = 'multi-proxy';
51726 for (var i = 0, len = selNodes.length; i < len; i++) {
51727 div.appendChild(selNodes[i].cloneNode(true));
51729 dragData.ddel = div;
51731 //console.log(dragData)
51732 //console.log(dragData.ddel.innerHTML)
51735 //console.log('nodragData')
51739 /** Specify to which ddGroup items in this DDView may be dragged. */
51740 setDraggable: function(ddGroup) {
51741 if (ddGroup instanceof Array) {
51742 Roo.each(ddGroup, this.setDraggable, this);
51745 if (this.dragZone) {
51746 this.dragZone.addToGroup(ddGroup);
51748 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
51749 containerScroll: true,
51753 // Draggability implies selection. DragZone's mousedown selects the element.
51754 if (!this.multiSelect) { this.singleSelect = true; }
51756 // Wire the DragZone's handlers up to methods in *this*
51757 this.dragZone.getDragData = this.getDragData.createDelegate(this);
51761 /** Specify from which ddGroup this DDView accepts drops. */
51762 setDroppable: function(ddGroup) {
51763 if (ddGroup instanceof Array) {
51764 Roo.each(ddGroup, this.setDroppable, this);
51767 if (this.dropZone) {
51768 this.dropZone.addToGroup(ddGroup);
51770 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
51771 containerScroll: true,
51775 // Wire the DropZone's handlers up to methods in *this*
51776 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
51777 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
51778 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
51779 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
51780 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
51784 /** Decide whether to drop above or below a View node. */
51785 getDropPoint : function(e, n, dd){
51786 if (n == this.el.dom) { return "above"; }
51787 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
51788 var c = t + (b - t) / 2;
51789 var y = Roo.lib.Event.getPageY(e);
51797 onNodeEnter : function(n, dd, e, data){
51801 onNodeOver : function(n, dd, e, data){
51802 var pt = this.getDropPoint(e, n, dd);
51803 // set the insert point style on the target node
51804 var dragElClass = this.dropNotAllowed;
51807 if (pt == "above"){
51808 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
51809 targetElClass = "x-view-drag-insert-above";
51811 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
51812 targetElClass = "x-view-drag-insert-below";
51814 if (this.lastInsertClass != targetElClass){
51815 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
51816 this.lastInsertClass = targetElClass;
51819 return dragElClass;
51822 onNodeOut : function(n, dd, e, data){
51823 this.removeDropIndicators(n);
51826 onNodeDrop : function(n, dd, e, data){
51827 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
51830 var pt = this.getDropPoint(e, n, dd);
51831 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
51832 if (pt == "below") { insertAt++; }
51833 for (var i = 0; i < data.records.length; i++) {
51834 var r = data.records[i];
51835 var dup = this.store.getById(r.id);
51836 if (dup && (dd != this.dragZone)) {
51837 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
51840 this.store.insert(insertAt++, r.copy());
51842 data.source.isDirtyFlag = true;
51844 this.store.insert(insertAt++, r);
51846 this.isDirtyFlag = true;
51849 this.dragZone.cachedTarget = null;
51853 removeDropIndicators : function(n){
51855 Roo.fly(n).removeClass([
51856 "x-view-drag-insert-above",
51857 "x-view-drag-insert-below"]);
51858 this.lastInsertClass = "_noclass";
51863 * Utility method. Add a delete option to the DDView's context menu.
51864 * @param {String} imageUrl The URL of the "delete" icon image.
51866 setDeletable: function(imageUrl) {
51867 if (!this.singleSelect && !this.multiSelect) {
51868 this.singleSelect = true;
51870 var c = this.getContextMenu();
51871 this.contextMenu.on("itemclick", function(item) {
51874 this.remove(this.getSelectedIndexes());
51878 this.contextMenu.add({
51885 /** Return the context menu for this DDView. */
51886 getContextMenu: function() {
51887 if (!this.contextMenu) {
51888 // Create the View's context menu
51889 this.contextMenu = new Roo.menu.Menu({
51890 id: this.id + "-contextmenu"
51892 this.el.on("contextmenu", this.showContextMenu, this);
51894 return this.contextMenu;
51897 disableContextMenu: function() {
51898 if (this.contextMenu) {
51899 this.el.un("contextmenu", this.showContextMenu, this);
51903 showContextMenu: function(e, item) {
51904 item = this.findItemFromChild(e.getTarget());
51907 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
51908 this.contextMenu.showAt(e.getXY());
51913 * Remove {@link Roo.data.Record}s at the specified indices.
51914 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
51916 remove: function(selectedIndices) {
51917 selectedIndices = [].concat(selectedIndices);
51918 for (var i = 0; i < selectedIndices.length; i++) {
51919 var rec = this.store.getAt(selectedIndices[i]);
51920 this.store.remove(rec);
51925 * Double click fires the event, but also, if this is draggable, and there is only one other
51926 * related DropZone, it transfers the selected node.
51928 onDblClick : function(e){
51929 var item = this.findItemFromChild(e.getTarget());
51931 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
51934 if (this.dragGroup) {
51935 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
51936 while (targets.indexOf(this.dropZone) > -1) {
51937 targets.remove(this.dropZone);
51939 if (targets.length == 1) {
51940 this.dragZone.cachedTarget = null;
51941 var el = Roo.get(targets[0].getEl());
51942 var box = el.getBox(true);
51943 targets[0].onNodeDrop(el.dom, {
51945 xy: [box.x, box.y + box.height - 1]
51946 }, null, this.getDragData(e));
51952 handleSelection: function(e) {
51953 this.dragZone.cachedTarget = null;
51954 var item = this.findItemFromChild(e.getTarget());
51956 this.clearSelections(true);
51959 if (item && (this.multiSelect || this.singleSelect)){
51960 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
51961 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
51962 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
51963 this.unselect(item);
51965 this.select(item, this.multiSelect && e.ctrlKey);
51966 this.lastSelection = item;
51971 onItemClick : function(item, index, e){
51972 if(this.fireEvent("beforeclick", this, index, item, e) === false){
51978 unselect : function(nodeInfo, suppressEvent){
51979 var node = this.getNode(nodeInfo);
51980 if(node && this.isSelected(node)){
51981 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
51982 Roo.fly(node).removeClass(this.selectedClass);
51983 this.selections.remove(node);
51984 if(!suppressEvent){
51985 this.fireEvent("selectionchange", this, this.selections);
51993 * Ext JS Library 1.1.1
51994 * Copyright(c) 2006-2007, Ext JS, LLC.
51996 * Originally Released Under LGPL - original licence link has changed is not relivant.
51999 * <script type="text/javascript">
52003 * @class Roo.LayoutManager
52004 * @extends Roo.util.Observable
52005 * Base class for layout managers.
52007 Roo.LayoutManager = function(container, config){
52008 Roo.LayoutManager.superclass.constructor.call(this);
52009 this.el = Roo.get(container);
52010 // ie scrollbar fix
52011 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
52012 document.body.scroll = "no";
52013 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
52014 this.el.position('relative');
52016 this.id = this.el.id;
52017 this.el.addClass("x-layout-container");
52018 /** false to disable window resize monitoring @type Boolean */
52019 this.monitorWindowResize = true;
52024 * Fires when a layout is performed.
52025 * @param {Roo.LayoutManager} this
52029 * @event regionresized
52030 * Fires when the user resizes a region.
52031 * @param {Roo.LayoutRegion} region The resized region
52032 * @param {Number} newSize The new size (width for east/west, height for north/south)
52034 "regionresized" : true,
52036 * @event regioncollapsed
52037 * Fires when a region is collapsed.
52038 * @param {Roo.LayoutRegion} region The collapsed region
52040 "regioncollapsed" : true,
52042 * @event regionexpanded
52043 * Fires when a region is expanded.
52044 * @param {Roo.LayoutRegion} region The expanded region
52046 "regionexpanded" : true
52048 this.updating = false;
52049 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
52052 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
52054 * Returns true if this layout is currently being updated
52055 * @return {Boolean}
52057 isUpdating : function(){
52058 return this.updating;
52062 * Suspend the LayoutManager from doing auto-layouts while
52063 * making multiple add or remove calls
52065 beginUpdate : function(){
52066 this.updating = true;
52070 * Restore auto-layouts and optionally disable the manager from performing a layout
52071 * @param {Boolean} noLayout true to disable a layout update
52073 endUpdate : function(noLayout){
52074 this.updating = false;
52080 layout: function(){
52084 onRegionResized : function(region, newSize){
52085 this.fireEvent("regionresized", region, newSize);
52089 onRegionCollapsed : function(region){
52090 this.fireEvent("regioncollapsed", region);
52093 onRegionExpanded : function(region){
52094 this.fireEvent("regionexpanded", region);
52098 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
52099 * performs box-model adjustments.
52100 * @return {Object} The size as an object {width: (the width), height: (the height)}
52102 getViewSize : function(){
52104 if(this.el.dom != document.body){
52105 size = this.el.getSize();
52107 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
52109 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
52110 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
52115 * Returns the Element this layout is bound to.
52116 * @return {Roo.Element}
52118 getEl : function(){
52123 * Returns the specified region.
52124 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
52125 * @return {Roo.LayoutRegion}
52127 getRegion : function(target){
52128 return this.regions[target.toLowerCase()];
52131 onWindowResize : function(){
52132 if(this.monitorWindowResize){
52138 * Ext JS Library 1.1.1
52139 * Copyright(c) 2006-2007, Ext JS, LLC.
52141 * Originally Released Under LGPL - original licence link has changed is not relivant.
52144 * <script type="text/javascript">
52147 * @class Roo.BorderLayout
52148 * @extends Roo.LayoutManager
52149 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
52150 * please see: <br><br>
52151 * <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>
52152 * <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>
52155 var layout = new Roo.BorderLayout(document.body, {
52189 preferredTabWidth: 150
52194 var CP = Roo.ContentPanel;
52196 layout.beginUpdate();
52197 layout.add("north", new CP("north", "North"));
52198 layout.add("south", new CP("south", {title: "South", closable: true}));
52199 layout.add("west", new CP("west", {title: "West"}));
52200 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
52201 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
52202 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
52203 layout.getRegion("center").showPanel("center1");
52204 layout.endUpdate();
52207 <b>The container the layout is rendered into can be either the body element or any other element.
52208 If it is not the body element, the container needs to either be an absolute positioned element,
52209 or you will need to add "position:relative" to the css of the container. You will also need to specify
52210 the container size if it is not the body element.</b>
52213 * Create a new BorderLayout
52214 * @param {String/HTMLElement/Element} container The container this layout is bound to
52215 * @param {Object} config Configuration options
52217 Roo.BorderLayout = function(container, config){
52218 config = config || {};
52219 Roo.BorderLayout.superclass.constructor.call(this, container, config);
52220 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
52221 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
52222 var target = this.factory.validRegions[i];
52223 if(config[target]){
52224 this.addRegion(target, config[target]);
52229 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
52231 * Creates and adds a new region if it doesn't already exist.
52232 * @param {String} target The target region key (north, south, east, west or center).
52233 * @param {Object} config The regions config object
52234 * @return {BorderLayoutRegion} The new region
52236 addRegion : function(target, config){
52237 if(!this.regions[target]){
52238 var r = this.factory.create(target, this, config);
52239 this.bindRegion(target, r);
52241 return this.regions[target];
52245 bindRegion : function(name, r){
52246 this.regions[name] = r;
52247 r.on("visibilitychange", this.layout, this);
52248 r.on("paneladded", this.layout, this);
52249 r.on("panelremoved", this.layout, this);
52250 r.on("invalidated", this.layout, this);
52251 r.on("resized", this.onRegionResized, this);
52252 r.on("collapsed", this.onRegionCollapsed, this);
52253 r.on("expanded", this.onRegionExpanded, this);
52257 * Performs a layout update.
52259 layout : function(){
52260 if(this.updating) {
52263 var size = this.getViewSize();
52264 var w = size.width;
52265 var h = size.height;
52270 //var x = 0, y = 0;
52272 var rs = this.regions;
52273 var north = rs["north"];
52274 var south = rs["south"];
52275 var west = rs["west"];
52276 var east = rs["east"];
52277 var center = rs["center"];
52278 //if(this.hideOnLayout){ // not supported anymore
52279 //c.el.setStyle("display", "none");
52281 if(north && north.isVisible()){
52282 var b = north.getBox();
52283 var m = north.getMargins();
52284 b.width = w - (m.left+m.right);
52287 centerY = b.height + b.y + m.bottom;
52288 centerH -= centerY;
52289 north.updateBox(this.safeBox(b));
52291 if(south && south.isVisible()){
52292 var b = south.getBox();
52293 var m = south.getMargins();
52294 b.width = w - (m.left+m.right);
52296 var totalHeight = (b.height + m.top + m.bottom);
52297 b.y = h - totalHeight + m.top;
52298 centerH -= totalHeight;
52299 south.updateBox(this.safeBox(b));
52301 if(west && west.isVisible()){
52302 var b = west.getBox();
52303 var m = west.getMargins();
52304 b.height = centerH - (m.top+m.bottom);
52306 b.y = centerY + m.top;
52307 var totalWidth = (b.width + m.left + m.right);
52308 centerX += totalWidth;
52309 centerW -= totalWidth;
52310 west.updateBox(this.safeBox(b));
52312 if(east && east.isVisible()){
52313 var b = east.getBox();
52314 var m = east.getMargins();
52315 b.height = centerH - (m.top+m.bottom);
52316 var totalWidth = (b.width + m.left + m.right);
52317 b.x = w - totalWidth + m.left;
52318 b.y = centerY + m.top;
52319 centerW -= totalWidth;
52320 east.updateBox(this.safeBox(b));
52323 var m = center.getMargins();
52325 x: centerX + m.left,
52326 y: centerY + m.top,
52327 width: centerW - (m.left+m.right),
52328 height: centerH - (m.top+m.bottom)
52330 //if(this.hideOnLayout){
52331 //center.el.setStyle("display", "block");
52333 center.updateBox(this.safeBox(centerBox));
52336 this.fireEvent("layout", this);
52340 safeBox : function(box){
52341 box.width = Math.max(0, box.width);
52342 box.height = Math.max(0, box.height);
52347 * Adds a ContentPanel (or subclass) to this layout.
52348 * @param {String} target The target region key (north, south, east, west or center).
52349 * @param {Roo.ContentPanel} panel The panel to add
52350 * @return {Roo.ContentPanel} The added panel
52352 add : function(target, panel){
52354 target = target.toLowerCase();
52355 return this.regions[target].add(panel);
52359 * Remove a ContentPanel (or subclass) to this layout.
52360 * @param {String} target The target region key (north, south, east, west or center).
52361 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
52362 * @return {Roo.ContentPanel} The removed panel
52364 remove : function(target, panel){
52365 target = target.toLowerCase();
52366 return this.regions[target].remove(panel);
52370 * Searches all regions for a panel with the specified id
52371 * @param {String} panelId
52372 * @return {Roo.ContentPanel} The panel or null if it wasn't found
52374 findPanel : function(panelId){
52375 var rs = this.regions;
52376 for(var target in rs){
52377 if(typeof rs[target] != "function"){
52378 var p = rs[target].getPanel(panelId);
52388 * Searches all regions for a panel with the specified id and activates (shows) it.
52389 * @param {String/ContentPanel} panelId The panels id or the panel itself
52390 * @return {Roo.ContentPanel} The shown panel or null
52392 showPanel : function(panelId) {
52393 var rs = this.regions;
52394 for(var target in rs){
52395 var r = rs[target];
52396 if(typeof r != "function"){
52397 if(r.hasPanel(panelId)){
52398 return r.showPanel(panelId);
52406 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
52407 * @param {Roo.state.Provider} provider (optional) An alternate state provider
52409 restoreState : function(provider){
52411 provider = Roo.state.Manager;
52413 var sm = new Roo.LayoutStateManager();
52414 sm.init(this, provider);
52418 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
52419 * object should contain properties for each region to add ContentPanels to, and each property's value should be
52420 * a valid ContentPanel config object. Example:
52422 // Create the main layout
52423 var layout = new Roo.BorderLayout('main-ct', {
52434 // Create and add multiple ContentPanels at once via configs
52437 id: 'source-files',
52439 title:'Ext Source Files',
52452 * @param {Object} regions An object containing ContentPanel configs by region name
52454 batchAdd : function(regions){
52455 this.beginUpdate();
52456 for(var rname in regions){
52457 var lr = this.regions[rname];
52459 this.addTypedPanels(lr, regions[rname]);
52466 addTypedPanels : function(lr, ps){
52467 if(typeof ps == 'string'){
52468 lr.add(new Roo.ContentPanel(ps));
52470 else if(ps instanceof Array){
52471 for(var i =0, len = ps.length; i < len; i++){
52472 this.addTypedPanels(lr, ps[i]);
52475 else if(!ps.events){ // raw config?
52477 delete ps.el; // prevent conflict
52478 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
52480 else { // panel object assumed!
52485 * Adds a xtype elements to the layout.
52489 xtype : 'ContentPanel',
52496 xtype : 'NestedLayoutPanel',
52502 items : [ ... list of content panels or nested layout panels.. ]
52506 * @param {Object} cfg Xtype definition of item to add.
52508 addxtype : function(cfg)
52510 // basically accepts a pannel...
52511 // can accept a layout region..!?!?
52512 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
52514 if (!cfg.xtype.match(/Panel$/)) {
52519 if (typeof(cfg.region) == 'undefined') {
52520 Roo.log("Failed to add Panel, region was not set");
52524 var region = cfg.region;
52530 xitems = cfg.items;
52537 case 'ContentPanel': // ContentPanel (el, cfg)
52538 case 'ScrollPanel': // ContentPanel (el, cfg)
52540 if(cfg.autoCreate) {
52541 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
52543 var el = this.el.createChild();
52544 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
52547 this.add(region, ret);
52551 case 'TreePanel': // our new panel!
52552 cfg.el = this.el.createChild();
52553 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
52554 this.add(region, ret);
52557 case 'NestedLayoutPanel':
52558 // create a new Layout (which is a Border Layout...
52559 var el = this.el.createChild();
52560 var clayout = cfg.layout;
52562 clayout.items = clayout.items || [];
52563 // replace this exitems with the clayout ones..
52564 xitems = clayout.items;
52567 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
52568 cfg.background = false;
52570 var layout = new Roo.BorderLayout(el, clayout);
52572 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
52573 //console.log('adding nested layout panel ' + cfg.toSource());
52574 this.add(region, ret);
52575 nb = {}; /// find first...
52580 // needs grid and region
52582 //var el = this.getRegion(region).el.createChild();
52583 var el = this.el.createChild();
52584 // create the grid first...
52586 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
52588 if (region == 'center' && this.active ) {
52589 cfg.background = false;
52591 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
52593 this.add(region, ret);
52594 if (cfg.background) {
52595 ret.on('activate', function(gp) {
52596 if (!gp.grid.rendered) {
52611 if (typeof(Roo[cfg.xtype]) != 'undefined') {
52613 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
52614 this.add(region, ret);
52617 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
52621 // GridPanel (grid, cfg)
52624 this.beginUpdate();
52628 Roo.each(xitems, function(i) {
52629 region = nb && i.region ? i.region : false;
52631 var add = ret.addxtype(i);
52634 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
52635 if (!i.background) {
52636 abn[region] = nb[region] ;
52643 // make the last non-background panel active..
52644 //if (nb) { Roo.log(abn); }
52647 for(var r in abn) {
52648 region = this.getRegion(r);
52650 // tried using nb[r], but it does not work..
52652 region.showPanel(abn[r]);
52663 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
52664 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
52665 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
52666 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
52669 var CP = Roo.ContentPanel;
52671 var layout = Roo.BorderLayout.create({
52675 panels: [new CP("north", "North")]
52684 panels: [new CP("west", {title: "West"})]
52693 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
52702 panels: [new CP("south", {title: "South", closable: true})]
52709 preferredTabWidth: 150,
52711 new CP("center1", {title: "Close Me", closable: true}),
52712 new CP("center2", {title: "Center Panel", closable: false})
52717 layout.getRegion("center").showPanel("center1");
52722 Roo.BorderLayout.create = function(config, targetEl){
52723 var layout = new Roo.BorderLayout(targetEl || document.body, config);
52724 layout.beginUpdate();
52725 var regions = Roo.BorderLayout.RegionFactory.validRegions;
52726 for(var j = 0, jlen = regions.length; j < jlen; j++){
52727 var lr = regions[j];
52728 if(layout.regions[lr] && config[lr].panels){
52729 var r = layout.regions[lr];
52730 var ps = config[lr].panels;
52731 layout.addTypedPanels(r, ps);
52734 layout.endUpdate();
52739 Roo.BorderLayout.RegionFactory = {
52741 validRegions : ["north","south","east","west","center"],
52744 create : function(target, mgr, config){
52745 target = target.toLowerCase();
52746 if(config.lightweight || config.basic){
52747 return new Roo.BasicLayoutRegion(mgr, config, target);
52751 return new Roo.NorthLayoutRegion(mgr, config);
52753 return new Roo.SouthLayoutRegion(mgr, config);
52755 return new Roo.EastLayoutRegion(mgr, config);
52757 return new Roo.WestLayoutRegion(mgr, config);
52759 return new Roo.CenterLayoutRegion(mgr, config);
52761 throw 'Layout region "'+target+'" not supported.';
52765 * Ext JS Library 1.1.1
52766 * Copyright(c) 2006-2007, Ext JS, LLC.
52768 * Originally Released Under LGPL - original licence link has changed is not relivant.
52771 * <script type="text/javascript">
52775 * @class Roo.BasicLayoutRegion
52776 * @extends Roo.util.Observable
52777 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
52778 * and does not have a titlebar, tabs or any other features. All it does is size and position
52779 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
52781 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
52783 this.position = pos;
52786 * @scope Roo.BasicLayoutRegion
52790 * @event beforeremove
52791 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
52792 * @param {Roo.LayoutRegion} this
52793 * @param {Roo.ContentPanel} panel The panel
52794 * @param {Object} e The cancel event object
52796 "beforeremove" : true,
52798 * @event invalidated
52799 * Fires when the layout for this region is changed.
52800 * @param {Roo.LayoutRegion} this
52802 "invalidated" : true,
52804 * @event visibilitychange
52805 * Fires when this region is shown or hidden
52806 * @param {Roo.LayoutRegion} this
52807 * @param {Boolean} visibility true or false
52809 "visibilitychange" : true,
52811 * @event paneladded
52812 * Fires when a panel is added.
52813 * @param {Roo.LayoutRegion} this
52814 * @param {Roo.ContentPanel} panel The panel
52816 "paneladded" : true,
52818 * @event panelremoved
52819 * Fires when a panel is removed.
52820 * @param {Roo.LayoutRegion} this
52821 * @param {Roo.ContentPanel} panel The panel
52823 "panelremoved" : true,
52825 * @event beforecollapse
52826 * Fires when this region before collapse.
52827 * @param {Roo.LayoutRegion} this
52829 "beforecollapse" : true,
52832 * Fires when this region is collapsed.
52833 * @param {Roo.LayoutRegion} this
52835 "collapsed" : true,
52838 * Fires when this region is expanded.
52839 * @param {Roo.LayoutRegion} this
52844 * Fires when this region is slid into view.
52845 * @param {Roo.LayoutRegion} this
52847 "slideshow" : true,
52850 * Fires when this region slides out of view.
52851 * @param {Roo.LayoutRegion} this
52853 "slidehide" : true,
52855 * @event panelactivated
52856 * Fires when a panel is activated.
52857 * @param {Roo.LayoutRegion} this
52858 * @param {Roo.ContentPanel} panel The activated panel
52860 "panelactivated" : true,
52863 * Fires when the user resizes this region.
52864 * @param {Roo.LayoutRegion} this
52865 * @param {Number} newSize The new size (width for east/west, height for north/south)
52869 /** A collection of panels in this region. @type Roo.util.MixedCollection */
52870 this.panels = new Roo.util.MixedCollection();
52871 this.panels.getKey = this.getPanelId.createDelegate(this);
52873 this.activePanel = null;
52874 // ensure listeners are added...
52876 if (config.listeners || config.events) {
52877 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
52878 listeners : config.listeners || {},
52879 events : config.events || {}
52883 if(skipConfig !== true){
52884 this.applyConfig(config);
52888 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
52889 getPanelId : function(p){
52893 applyConfig : function(config){
52894 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
52895 this.config = config;
52900 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
52901 * the width, for horizontal (north, south) the height.
52902 * @param {Number} newSize The new width or height
52904 resizeTo : function(newSize){
52905 var el = this.el ? this.el :
52906 (this.activePanel ? this.activePanel.getEl() : null);
52908 switch(this.position){
52911 el.setWidth(newSize);
52912 this.fireEvent("resized", this, newSize);
52916 el.setHeight(newSize);
52917 this.fireEvent("resized", this, newSize);
52923 getBox : function(){
52924 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
52927 getMargins : function(){
52928 return this.margins;
52931 updateBox : function(box){
52933 var el = this.activePanel.getEl();
52934 el.dom.style.left = box.x + "px";
52935 el.dom.style.top = box.y + "px";
52936 this.activePanel.setSize(box.width, box.height);
52940 * Returns the container element for this region.
52941 * @return {Roo.Element}
52943 getEl : function(){
52944 return this.activePanel;
52948 * Returns true if this region is currently visible.
52949 * @return {Boolean}
52951 isVisible : function(){
52952 return this.activePanel ? true : false;
52955 setActivePanel : function(panel){
52956 panel = this.getPanel(panel);
52957 if(this.activePanel && this.activePanel != panel){
52958 this.activePanel.setActiveState(false);
52959 this.activePanel.getEl().setLeftTop(-10000,-10000);
52961 this.activePanel = panel;
52962 panel.setActiveState(true);
52964 panel.setSize(this.box.width, this.box.height);
52966 this.fireEvent("panelactivated", this, panel);
52967 this.fireEvent("invalidated");
52971 * Show the specified panel.
52972 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
52973 * @return {Roo.ContentPanel} The shown panel or null
52975 showPanel : function(panel){
52976 if(panel = this.getPanel(panel)){
52977 this.setActivePanel(panel);
52983 * Get the active panel for this region.
52984 * @return {Roo.ContentPanel} The active panel or null
52986 getActivePanel : function(){
52987 return this.activePanel;
52991 * Add the passed ContentPanel(s)
52992 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
52993 * @return {Roo.ContentPanel} The panel added (if only one was added)
52995 add : function(panel){
52996 if(arguments.length > 1){
52997 for(var i = 0, len = arguments.length; i < len; i++) {
52998 this.add(arguments[i]);
53002 if(this.hasPanel(panel)){
53003 this.showPanel(panel);
53006 var el = panel.getEl();
53007 if(el.dom.parentNode != this.mgr.el.dom){
53008 this.mgr.el.dom.appendChild(el.dom);
53010 if(panel.setRegion){
53011 panel.setRegion(this);
53013 this.panels.add(panel);
53014 el.setStyle("position", "absolute");
53015 if(!panel.background){
53016 this.setActivePanel(panel);
53017 if(this.config.initialSize && this.panels.getCount()==1){
53018 this.resizeTo(this.config.initialSize);
53021 this.fireEvent("paneladded", this, panel);
53026 * Returns true if the panel is in this region.
53027 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
53028 * @return {Boolean}
53030 hasPanel : function(panel){
53031 if(typeof panel == "object"){ // must be panel obj
53032 panel = panel.getId();
53034 return this.getPanel(panel) ? true : false;
53038 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
53039 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
53040 * @param {Boolean} preservePanel Overrides the config preservePanel option
53041 * @return {Roo.ContentPanel} The panel that was removed
53043 remove : function(panel, preservePanel){
53044 panel = this.getPanel(panel);
53049 this.fireEvent("beforeremove", this, panel, e);
53050 if(e.cancel === true){
53053 var panelId = panel.getId();
53054 this.panels.removeKey(panelId);
53059 * Returns the panel specified or null if it's not in this region.
53060 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
53061 * @return {Roo.ContentPanel}
53063 getPanel : function(id){
53064 if(typeof id == "object"){ // must be panel obj
53067 return this.panels.get(id);
53071 * Returns this regions position (north/south/east/west/center).
53074 getPosition: function(){
53075 return this.position;
53079 * Ext JS Library 1.1.1
53080 * Copyright(c) 2006-2007, Ext JS, LLC.
53082 * Originally Released Under LGPL - original licence link has changed is not relivant.
53085 * <script type="text/javascript">
53089 * @class Roo.LayoutRegion
53090 * @extends Roo.BasicLayoutRegion
53091 * This class represents a region in a layout manager.
53092 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
53093 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
53094 * @cfg {Boolean} floatable False to disable floating (defaults to true)
53095 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
53096 * @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})
53097 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
53098 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
53099 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
53100 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
53101 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
53102 * @cfg {String} title The title for the region (overrides panel titles)
53103 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
53104 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
53105 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
53106 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
53107 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
53108 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
53109 * the space available, similar to FireFox 1.5 tabs (defaults to false)
53110 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
53111 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
53112 * @cfg {Boolean} showPin True to show a pin button
53113 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
53114 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
53115 * @cfg {Boolean} disableTabTips True to disable tab tooltips
53116 * @cfg {Number} width For East/West panels
53117 * @cfg {Number} height For North/South panels
53118 * @cfg {Boolean} split To show the splitter
53119 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
53121 Roo.LayoutRegion = function(mgr, config, pos){
53122 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
53123 var dh = Roo.DomHelper;
53124 /** This region's container element
53125 * @type Roo.Element */
53126 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
53127 /** This region's title element
53128 * @type Roo.Element */
53130 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
53131 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
53132 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
53134 this.titleEl.enableDisplayMode();
53135 /** This region's title text element
53136 * @type HTMLElement */
53137 this.titleTextEl = this.titleEl.dom.firstChild;
53138 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
53139 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
53140 this.closeBtn.enableDisplayMode();
53141 this.closeBtn.on("click", this.closeClicked, this);
53142 this.closeBtn.hide();
53144 this.createBody(config);
53145 this.visible = true;
53146 this.collapsed = false;
53148 if(config.hideWhenEmpty){
53150 this.on("paneladded", this.validateVisibility, this);
53151 this.on("panelremoved", this.validateVisibility, this);
53153 this.applyConfig(config);
53156 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
53158 createBody : function(){
53159 /** This region's body element
53160 * @type Roo.Element */
53161 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
53164 applyConfig : function(c){
53165 if(c.collapsible && this.position != "center" && !this.collapsedEl){
53166 var dh = Roo.DomHelper;
53167 if(c.titlebar !== false){
53168 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
53169 this.collapseBtn.on("click", this.collapse, this);
53170 this.collapseBtn.enableDisplayMode();
53172 if(c.showPin === true || this.showPin){
53173 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
53174 this.stickBtn.enableDisplayMode();
53175 this.stickBtn.on("click", this.expand, this);
53176 this.stickBtn.hide();
53179 /** This region's collapsed element
53180 * @type Roo.Element */
53181 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
53182 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
53184 if(c.floatable !== false){
53185 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
53186 this.collapsedEl.on("click", this.collapseClick, this);
53189 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
53190 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
53191 id: "message", unselectable: "on", style:{"float":"left"}});
53192 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
53194 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
53195 this.expandBtn.on("click", this.expand, this);
53197 if(this.collapseBtn){
53198 this.collapseBtn.setVisible(c.collapsible == true);
53200 this.cmargins = c.cmargins || this.cmargins ||
53201 (this.position == "west" || this.position == "east" ?
53202 {top: 0, left: 2, right:2, bottom: 0} :
53203 {top: 2, left: 0, right:0, bottom: 2});
53204 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
53205 this.bottomTabs = c.tabPosition != "top";
53206 this.autoScroll = c.autoScroll || false;
53207 if(this.autoScroll){
53208 this.bodyEl.setStyle("overflow", "auto");
53210 this.bodyEl.setStyle("overflow", "hidden");
53212 //if(c.titlebar !== false){
53213 if((!c.titlebar && !c.title) || c.titlebar === false){
53214 this.titleEl.hide();
53216 this.titleEl.show();
53218 this.titleTextEl.innerHTML = c.title;
53222 this.duration = c.duration || .30;
53223 this.slideDuration = c.slideDuration || .45;
53226 this.collapse(true);
53233 * Returns true if this region is currently visible.
53234 * @return {Boolean}
53236 isVisible : function(){
53237 return this.visible;
53241 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
53242 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
53244 setCollapsedTitle : function(title){
53245 title = title || " ";
53246 if(this.collapsedTitleTextEl){
53247 this.collapsedTitleTextEl.innerHTML = title;
53251 getBox : function(){
53253 if(!this.collapsed){
53254 b = this.el.getBox(false, true);
53256 b = this.collapsedEl.getBox(false, true);
53261 getMargins : function(){
53262 return this.collapsed ? this.cmargins : this.margins;
53265 highlight : function(){
53266 this.el.addClass("x-layout-panel-dragover");
53269 unhighlight : function(){
53270 this.el.removeClass("x-layout-panel-dragover");
53273 updateBox : function(box){
53275 if(!this.collapsed){
53276 this.el.dom.style.left = box.x + "px";
53277 this.el.dom.style.top = box.y + "px";
53278 this.updateBody(box.width, box.height);
53280 this.collapsedEl.dom.style.left = box.x + "px";
53281 this.collapsedEl.dom.style.top = box.y + "px";
53282 this.collapsedEl.setSize(box.width, box.height);
53285 this.tabs.autoSizeTabs();
53289 updateBody : function(w, h){
53291 this.el.setWidth(w);
53292 w -= this.el.getBorderWidth("rl");
53293 if(this.config.adjustments){
53294 w += this.config.adjustments[0];
53298 this.el.setHeight(h);
53299 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
53300 h -= this.el.getBorderWidth("tb");
53301 if(this.config.adjustments){
53302 h += this.config.adjustments[1];
53304 this.bodyEl.setHeight(h);
53306 h = this.tabs.syncHeight(h);
53309 if(this.panelSize){
53310 w = w !== null ? w : this.panelSize.width;
53311 h = h !== null ? h : this.panelSize.height;
53313 if(this.activePanel){
53314 var el = this.activePanel.getEl();
53315 w = w !== null ? w : el.getWidth();
53316 h = h !== null ? h : el.getHeight();
53317 this.panelSize = {width: w, height: h};
53318 this.activePanel.setSize(w, h);
53320 if(Roo.isIE && this.tabs){
53321 this.tabs.el.repaint();
53326 * Returns the container element for this region.
53327 * @return {Roo.Element}
53329 getEl : function(){
53334 * Hides this region.
53337 if(!this.collapsed){
53338 this.el.dom.style.left = "-2000px";
53341 this.collapsedEl.dom.style.left = "-2000px";
53342 this.collapsedEl.hide();
53344 this.visible = false;
53345 this.fireEvent("visibilitychange", this, false);
53349 * Shows this region if it was previously hidden.
53352 if(!this.collapsed){
53355 this.collapsedEl.show();
53357 this.visible = true;
53358 this.fireEvent("visibilitychange", this, true);
53361 closeClicked : function(){
53362 if(this.activePanel){
53363 this.remove(this.activePanel);
53367 collapseClick : function(e){
53369 e.stopPropagation();
53372 e.stopPropagation();
53378 * Collapses this region.
53379 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
53381 collapse : function(skipAnim, skipCheck){
53382 if(this.collapsed) {
53386 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
53388 this.collapsed = true;
53390 this.split.el.hide();
53392 if(this.config.animate && skipAnim !== true){
53393 this.fireEvent("invalidated", this);
53394 this.animateCollapse();
53396 this.el.setLocation(-20000,-20000);
53398 this.collapsedEl.show();
53399 this.fireEvent("collapsed", this);
53400 this.fireEvent("invalidated", this);
53406 animateCollapse : function(){
53411 * Expands this region if it was previously collapsed.
53412 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
53413 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
53415 expand : function(e, skipAnim){
53417 e.stopPropagation();
53419 if(!this.collapsed || this.el.hasActiveFx()) {
53423 this.afterSlideIn();
53426 this.collapsed = false;
53427 if(this.config.animate && skipAnim !== true){
53428 this.animateExpand();
53432 this.split.el.show();
53434 this.collapsedEl.setLocation(-2000,-2000);
53435 this.collapsedEl.hide();
53436 this.fireEvent("invalidated", this);
53437 this.fireEvent("expanded", this);
53441 animateExpand : function(){
53445 initTabs : function()
53447 this.bodyEl.setStyle("overflow", "hidden");
53448 var ts = new Roo.TabPanel(
53451 tabPosition: this.bottomTabs ? 'bottom' : 'top',
53452 disableTooltips: this.config.disableTabTips,
53453 toolbar : this.config.toolbar
53456 if(this.config.hideTabs){
53457 ts.stripWrap.setDisplayed(false);
53460 ts.resizeTabs = this.config.resizeTabs === true;
53461 ts.minTabWidth = this.config.minTabWidth || 40;
53462 ts.maxTabWidth = this.config.maxTabWidth || 250;
53463 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
53464 ts.monitorResize = false;
53465 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
53466 ts.bodyEl.addClass('x-layout-tabs-body');
53467 this.panels.each(this.initPanelAsTab, this);
53470 initPanelAsTab : function(panel){
53471 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
53472 this.config.closeOnTab && panel.isClosable());
53473 if(panel.tabTip !== undefined){
53474 ti.setTooltip(panel.tabTip);
53476 ti.on("activate", function(){
53477 this.setActivePanel(panel);
53479 if(this.config.closeOnTab){
53480 ti.on("beforeclose", function(t, e){
53482 this.remove(panel);
53488 updatePanelTitle : function(panel, title){
53489 if(this.activePanel == panel){
53490 this.updateTitle(title);
53493 var ti = this.tabs.getTab(panel.getEl().id);
53495 if(panel.tabTip !== undefined){
53496 ti.setTooltip(panel.tabTip);
53501 updateTitle : function(title){
53502 if(this.titleTextEl && !this.config.title){
53503 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
53507 setActivePanel : function(panel){
53508 panel = this.getPanel(panel);
53509 if(this.activePanel && this.activePanel != panel){
53510 this.activePanel.setActiveState(false);
53512 this.activePanel = panel;
53513 panel.setActiveState(true);
53514 if(this.panelSize){
53515 panel.setSize(this.panelSize.width, this.panelSize.height);
53518 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
53520 this.updateTitle(panel.getTitle());
53522 this.fireEvent("invalidated", this);
53524 this.fireEvent("panelactivated", this, panel);
53528 * Shows the specified panel.
53529 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
53530 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
53532 showPanel : function(panel)
53534 panel = this.getPanel(panel);
53537 var tab = this.tabs.getTab(panel.getEl().id);
53538 if(tab.isHidden()){
53539 this.tabs.unhideTab(tab.id);
53543 this.setActivePanel(panel);
53550 * Get the active panel for this region.
53551 * @return {Roo.ContentPanel} The active panel or null
53553 getActivePanel : function(){
53554 return this.activePanel;
53557 validateVisibility : function(){
53558 if(this.panels.getCount() < 1){
53559 this.updateTitle(" ");
53560 this.closeBtn.hide();
53563 if(!this.isVisible()){
53570 * Adds the passed ContentPanel(s) to this region.
53571 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
53572 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
53574 add : function(panel){
53575 if(arguments.length > 1){
53576 for(var i = 0, len = arguments.length; i < len; i++) {
53577 this.add(arguments[i]);
53581 if(this.hasPanel(panel)){
53582 this.showPanel(panel);
53585 panel.setRegion(this);
53586 this.panels.add(panel);
53587 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
53588 this.bodyEl.dom.appendChild(panel.getEl().dom);
53589 if(panel.background !== true){
53590 this.setActivePanel(panel);
53592 this.fireEvent("paneladded", this, panel);
53598 this.initPanelAsTab(panel);
53600 if(panel.background !== true){
53601 this.tabs.activate(panel.getEl().id);
53603 this.fireEvent("paneladded", this, panel);
53608 * Hides the tab for the specified panel.
53609 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
53611 hidePanel : function(panel){
53612 if(this.tabs && (panel = this.getPanel(panel))){
53613 this.tabs.hideTab(panel.getEl().id);
53618 * Unhides the tab for a previously hidden panel.
53619 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
53621 unhidePanel : function(panel){
53622 if(this.tabs && (panel = this.getPanel(panel))){
53623 this.tabs.unhideTab(panel.getEl().id);
53627 clearPanels : function(){
53628 while(this.panels.getCount() > 0){
53629 this.remove(this.panels.first());
53634 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
53635 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
53636 * @param {Boolean} preservePanel Overrides the config preservePanel option
53637 * @return {Roo.ContentPanel} The panel that was removed
53639 remove : function(panel, preservePanel){
53640 panel = this.getPanel(panel);
53645 this.fireEvent("beforeremove", this, panel, e);
53646 if(e.cancel === true){
53649 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
53650 var panelId = panel.getId();
53651 this.panels.removeKey(panelId);
53653 document.body.appendChild(panel.getEl().dom);
53656 this.tabs.removeTab(panel.getEl().id);
53657 }else if (!preservePanel){
53658 this.bodyEl.dom.removeChild(panel.getEl().dom);
53660 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
53661 var p = this.panels.first();
53662 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
53663 tempEl.appendChild(p.getEl().dom);
53664 this.bodyEl.update("");
53665 this.bodyEl.dom.appendChild(p.getEl().dom);
53667 this.updateTitle(p.getTitle());
53669 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
53670 this.setActivePanel(p);
53672 panel.setRegion(null);
53673 if(this.activePanel == panel){
53674 this.activePanel = null;
53676 if(this.config.autoDestroy !== false && preservePanel !== true){
53677 try{panel.destroy();}catch(e){}
53679 this.fireEvent("panelremoved", this, panel);
53684 * Returns the TabPanel component used by this region
53685 * @return {Roo.TabPanel}
53687 getTabs : function(){
53691 createTool : function(parentEl, className){
53692 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
53693 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
53694 btn.addClassOnOver("x-layout-tools-button-over");
53699 * Ext JS Library 1.1.1
53700 * Copyright(c) 2006-2007, Ext JS, LLC.
53702 * Originally Released Under LGPL - original licence link has changed is not relivant.
53705 * <script type="text/javascript">
53711 * @class Roo.SplitLayoutRegion
53712 * @extends Roo.LayoutRegion
53713 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
53715 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
53716 this.cursor = cursor;
53717 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
53720 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
53721 splitTip : "Drag to resize.",
53722 collapsibleSplitTip : "Drag to resize. Double click to hide.",
53723 useSplitTips : false,
53725 applyConfig : function(config){
53726 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
53729 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
53730 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
53731 /** The SplitBar for this region
53732 * @type Roo.SplitBar */
53733 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
53734 this.split.on("moved", this.onSplitMove, this);
53735 this.split.useShim = config.useShim === true;
53736 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
53737 if(this.useSplitTips){
53738 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
53740 if(config.collapsible){
53741 this.split.el.on("dblclick", this.collapse, this);
53744 if(typeof config.minSize != "undefined"){
53745 this.split.minSize = config.minSize;
53747 if(typeof config.maxSize != "undefined"){
53748 this.split.maxSize = config.maxSize;
53750 if(config.hideWhenEmpty || config.hidden || config.collapsed){
53751 this.hideSplitter();
53756 getHMaxSize : function(){
53757 var cmax = this.config.maxSize || 10000;
53758 var center = this.mgr.getRegion("center");
53759 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
53762 getVMaxSize : function(){
53763 var cmax = this.config.maxSize || 10000;
53764 var center = this.mgr.getRegion("center");
53765 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
53768 onSplitMove : function(split, newSize){
53769 this.fireEvent("resized", this, newSize);
53773 * Returns the {@link Roo.SplitBar} for this region.
53774 * @return {Roo.SplitBar}
53776 getSplitBar : function(){
53781 this.hideSplitter();
53782 Roo.SplitLayoutRegion.superclass.hide.call(this);
53785 hideSplitter : function(){
53787 this.split.el.setLocation(-2000,-2000);
53788 this.split.el.hide();
53794 this.split.el.show();
53796 Roo.SplitLayoutRegion.superclass.show.call(this);
53799 beforeSlide: function(){
53800 if(Roo.isGecko){// firefox overflow auto bug workaround
53801 this.bodyEl.clip();
53803 this.tabs.bodyEl.clip();
53805 if(this.activePanel){
53806 this.activePanel.getEl().clip();
53808 if(this.activePanel.beforeSlide){
53809 this.activePanel.beforeSlide();
53815 afterSlide : function(){
53816 if(Roo.isGecko){// firefox overflow auto bug workaround
53817 this.bodyEl.unclip();
53819 this.tabs.bodyEl.unclip();
53821 if(this.activePanel){
53822 this.activePanel.getEl().unclip();
53823 if(this.activePanel.afterSlide){
53824 this.activePanel.afterSlide();
53830 initAutoHide : function(){
53831 if(this.autoHide !== false){
53832 if(!this.autoHideHd){
53833 var st = new Roo.util.DelayedTask(this.slideIn, this);
53834 this.autoHideHd = {
53835 "mouseout": function(e){
53836 if(!e.within(this.el, true)){
53840 "mouseover" : function(e){
53846 this.el.on(this.autoHideHd);
53850 clearAutoHide : function(){
53851 if(this.autoHide !== false){
53852 this.el.un("mouseout", this.autoHideHd.mouseout);
53853 this.el.un("mouseover", this.autoHideHd.mouseover);
53857 clearMonitor : function(){
53858 Roo.get(document).un("click", this.slideInIf, this);
53861 // these names are backwards but not changed for compat
53862 slideOut : function(){
53863 if(this.isSlid || this.el.hasActiveFx()){
53866 this.isSlid = true;
53867 if(this.collapseBtn){
53868 this.collapseBtn.hide();
53870 this.closeBtnState = this.closeBtn.getStyle('display');
53871 this.closeBtn.hide();
53873 this.stickBtn.show();
53876 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
53877 this.beforeSlide();
53878 this.el.setStyle("z-index", 10001);
53879 this.el.slideIn(this.getSlideAnchor(), {
53880 callback: function(){
53882 this.initAutoHide();
53883 Roo.get(document).on("click", this.slideInIf, this);
53884 this.fireEvent("slideshow", this);
53891 afterSlideIn : function(){
53892 this.clearAutoHide();
53893 this.isSlid = false;
53894 this.clearMonitor();
53895 this.el.setStyle("z-index", "");
53896 if(this.collapseBtn){
53897 this.collapseBtn.show();
53899 this.closeBtn.setStyle('display', this.closeBtnState);
53901 this.stickBtn.hide();
53903 this.fireEvent("slidehide", this);
53906 slideIn : function(cb){
53907 if(!this.isSlid || this.el.hasActiveFx()){
53911 this.isSlid = false;
53912 this.beforeSlide();
53913 this.el.slideOut(this.getSlideAnchor(), {
53914 callback: function(){
53915 this.el.setLeftTop(-10000, -10000);
53917 this.afterSlideIn();
53925 slideInIf : function(e){
53926 if(!e.within(this.el)){
53931 animateCollapse : function(){
53932 this.beforeSlide();
53933 this.el.setStyle("z-index", 20000);
53934 var anchor = this.getSlideAnchor();
53935 this.el.slideOut(anchor, {
53936 callback : function(){
53937 this.el.setStyle("z-index", "");
53938 this.collapsedEl.slideIn(anchor, {duration:.3});
53940 this.el.setLocation(-10000,-10000);
53942 this.fireEvent("collapsed", this);
53949 animateExpand : function(){
53950 this.beforeSlide();
53951 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
53952 this.el.setStyle("z-index", 20000);
53953 this.collapsedEl.hide({
53956 this.el.slideIn(this.getSlideAnchor(), {
53957 callback : function(){
53958 this.el.setStyle("z-index", "");
53961 this.split.el.show();
53963 this.fireEvent("invalidated", this);
53964 this.fireEvent("expanded", this);
53992 getAnchor : function(){
53993 return this.anchors[this.position];
53996 getCollapseAnchor : function(){
53997 return this.canchors[this.position];
54000 getSlideAnchor : function(){
54001 return this.sanchors[this.position];
54004 getAlignAdj : function(){
54005 var cm = this.cmargins;
54006 switch(this.position){
54022 getExpandAdj : function(){
54023 var c = this.collapsedEl, cm = this.cmargins;
54024 switch(this.position){
54026 return [-(cm.right+c.getWidth()+cm.left), 0];
54029 return [cm.right+c.getWidth()+cm.left, 0];
54032 return [0, -(cm.top+cm.bottom+c.getHeight())];
54035 return [0, cm.top+cm.bottom+c.getHeight()];
54041 * Ext JS Library 1.1.1
54042 * Copyright(c) 2006-2007, Ext JS, LLC.
54044 * Originally Released Under LGPL - original licence link has changed is not relivant.
54047 * <script type="text/javascript">
54050 * These classes are private internal classes
54052 Roo.CenterLayoutRegion = function(mgr, config){
54053 Roo.LayoutRegion.call(this, mgr, config, "center");
54054 this.visible = true;
54055 this.minWidth = config.minWidth || 20;
54056 this.minHeight = config.minHeight || 20;
54059 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
54061 // center panel can't be hidden
54065 // center panel can't be hidden
54068 getMinWidth: function(){
54069 return this.minWidth;
54072 getMinHeight: function(){
54073 return this.minHeight;
54078 Roo.NorthLayoutRegion = function(mgr, config){
54079 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
54081 this.split.placement = Roo.SplitBar.TOP;
54082 this.split.orientation = Roo.SplitBar.VERTICAL;
54083 this.split.el.addClass("x-layout-split-v");
54085 var size = config.initialSize || config.height;
54086 if(typeof size != "undefined"){
54087 this.el.setHeight(size);
54090 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
54091 orientation: Roo.SplitBar.VERTICAL,
54092 getBox : function(){
54093 if(this.collapsed){
54094 return this.collapsedEl.getBox();
54096 var box = this.el.getBox();
54098 box.height += this.split.el.getHeight();
54103 updateBox : function(box){
54104 if(this.split && !this.collapsed){
54105 box.height -= this.split.el.getHeight();
54106 this.split.el.setLeft(box.x);
54107 this.split.el.setTop(box.y+box.height);
54108 this.split.el.setWidth(box.width);
54110 if(this.collapsed){
54111 this.updateBody(box.width, null);
54113 Roo.LayoutRegion.prototype.updateBox.call(this, box);
54117 Roo.SouthLayoutRegion = function(mgr, config){
54118 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
54120 this.split.placement = Roo.SplitBar.BOTTOM;
54121 this.split.orientation = Roo.SplitBar.VERTICAL;
54122 this.split.el.addClass("x-layout-split-v");
54124 var size = config.initialSize || config.height;
54125 if(typeof size != "undefined"){
54126 this.el.setHeight(size);
54129 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
54130 orientation: Roo.SplitBar.VERTICAL,
54131 getBox : function(){
54132 if(this.collapsed){
54133 return this.collapsedEl.getBox();
54135 var box = this.el.getBox();
54137 var sh = this.split.el.getHeight();
54144 updateBox : function(box){
54145 if(this.split && !this.collapsed){
54146 var sh = this.split.el.getHeight();
54149 this.split.el.setLeft(box.x);
54150 this.split.el.setTop(box.y-sh);
54151 this.split.el.setWidth(box.width);
54153 if(this.collapsed){
54154 this.updateBody(box.width, null);
54156 Roo.LayoutRegion.prototype.updateBox.call(this, box);
54160 Roo.EastLayoutRegion = function(mgr, config){
54161 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
54163 this.split.placement = Roo.SplitBar.RIGHT;
54164 this.split.orientation = Roo.SplitBar.HORIZONTAL;
54165 this.split.el.addClass("x-layout-split-h");
54167 var size = config.initialSize || config.width;
54168 if(typeof size != "undefined"){
54169 this.el.setWidth(size);
54172 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
54173 orientation: Roo.SplitBar.HORIZONTAL,
54174 getBox : function(){
54175 if(this.collapsed){
54176 return this.collapsedEl.getBox();
54178 var box = this.el.getBox();
54180 var sw = this.split.el.getWidth();
54187 updateBox : function(box){
54188 if(this.split && !this.collapsed){
54189 var sw = this.split.el.getWidth();
54191 this.split.el.setLeft(box.x);
54192 this.split.el.setTop(box.y);
54193 this.split.el.setHeight(box.height);
54196 if(this.collapsed){
54197 this.updateBody(null, box.height);
54199 Roo.LayoutRegion.prototype.updateBox.call(this, box);
54203 Roo.WestLayoutRegion = function(mgr, config){
54204 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
54206 this.split.placement = Roo.SplitBar.LEFT;
54207 this.split.orientation = Roo.SplitBar.HORIZONTAL;
54208 this.split.el.addClass("x-layout-split-h");
54210 var size = config.initialSize || config.width;
54211 if(typeof size != "undefined"){
54212 this.el.setWidth(size);
54215 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
54216 orientation: Roo.SplitBar.HORIZONTAL,
54217 getBox : function(){
54218 if(this.collapsed){
54219 return this.collapsedEl.getBox();
54221 var box = this.el.getBox();
54223 box.width += this.split.el.getWidth();
54228 updateBox : function(box){
54229 if(this.split && !this.collapsed){
54230 var sw = this.split.el.getWidth();
54232 this.split.el.setLeft(box.x+box.width);
54233 this.split.el.setTop(box.y);
54234 this.split.el.setHeight(box.height);
54236 if(this.collapsed){
54237 this.updateBody(null, box.height);
54239 Roo.LayoutRegion.prototype.updateBox.call(this, box);
54244 * Ext JS Library 1.1.1
54245 * Copyright(c) 2006-2007, Ext JS, LLC.
54247 * Originally Released Under LGPL - original licence link has changed is not relivant.
54250 * <script type="text/javascript">
54255 * Private internal class for reading and applying state
54257 Roo.LayoutStateManager = function(layout){
54258 // default empty state
54267 Roo.LayoutStateManager.prototype = {
54268 init : function(layout, provider){
54269 this.provider = provider;
54270 var state = provider.get(layout.id+"-layout-state");
54272 var wasUpdating = layout.isUpdating();
54274 layout.beginUpdate();
54276 for(var key in state){
54277 if(typeof state[key] != "function"){
54278 var rstate = state[key];
54279 var r = layout.getRegion(key);
54282 r.resizeTo(rstate.size);
54284 if(rstate.collapsed == true){
54287 r.expand(null, true);
54293 layout.endUpdate();
54295 this.state = state;
54297 this.layout = layout;
54298 layout.on("regionresized", this.onRegionResized, this);
54299 layout.on("regioncollapsed", this.onRegionCollapsed, this);
54300 layout.on("regionexpanded", this.onRegionExpanded, this);
54303 storeState : function(){
54304 this.provider.set(this.layout.id+"-layout-state", this.state);
54307 onRegionResized : function(region, newSize){
54308 this.state[region.getPosition()].size = newSize;
54312 onRegionCollapsed : function(region){
54313 this.state[region.getPosition()].collapsed = true;
54317 onRegionExpanded : function(region){
54318 this.state[region.getPosition()].collapsed = false;
54323 * Ext JS Library 1.1.1
54324 * Copyright(c) 2006-2007, Ext JS, LLC.
54326 * Originally Released Under LGPL - original licence link has changed is not relivant.
54329 * <script type="text/javascript">
54332 * @class Roo.ContentPanel
54333 * @extends Roo.util.Observable
54334 * A basic ContentPanel element.
54335 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
54336 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
54337 * @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
54338 * @cfg {Boolean} closable True if the panel can be closed/removed
54339 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
54340 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
54341 * @cfg {Toolbar} toolbar A toolbar for this panel
54342 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
54343 * @cfg {String} title The title for this panel
54344 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
54345 * @cfg {String} url Calls {@link #setUrl} with this value
54346 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
54347 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
54348 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
54349 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
54350 * @cfg {String} style Extra style to add to the content panel
54353 * Create a new ContentPanel.
54354 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
54355 * @param {String/Object} config A string to set only the title or a config object
54356 * @param {String} content (optional) Set the HTML content for this panel
54357 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
54359 Roo.ContentPanel = function(el, config, content){
54363 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
54367 if (config && config.parentLayout) {
54368 el = config.parentLayout.el.createChild();
54371 if(el.autoCreate){ // xtype is available if this is called from factory
54375 this.el = Roo.get(el);
54376 if(!this.el && config && config.autoCreate){
54377 if(typeof config.autoCreate == "object"){
54378 if(!config.autoCreate.id){
54379 config.autoCreate.id = config.id||el;
54381 this.el = Roo.DomHelper.append(document.body,
54382 config.autoCreate, true);
54384 this.el = Roo.DomHelper.append(document.body,
54385 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
54390 this.closable = false;
54391 this.loaded = false;
54392 this.active = false;
54393 if(typeof config == "string"){
54394 this.title = config;
54396 Roo.apply(this, config);
54399 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
54400 this.wrapEl = this.el.wrap();
54401 this.toolbar.container = this.el.insertSibling(false, 'before');
54402 this.toolbar = new Roo.Toolbar(this.toolbar);
54405 // xtype created footer. - not sure if will work as we normally have to render first..
54406 if (this.footer && !this.footer.el && this.footer.xtype) {
54407 if (!this.wrapEl) {
54408 this.wrapEl = this.el.wrap();
54411 this.footer.container = this.wrapEl.createChild();
54413 this.footer = Roo.factory(this.footer, Roo);
54418 this.resizeEl = Roo.get(this.resizeEl, true);
54420 this.resizeEl = this.el;
54422 // handle view.xtype
54430 * Fires when this panel is activated.
54431 * @param {Roo.ContentPanel} this
54435 * @event deactivate
54436 * Fires when this panel is activated.
54437 * @param {Roo.ContentPanel} this
54439 "deactivate" : true,
54443 * Fires when this panel is resized if fitToFrame is true.
54444 * @param {Roo.ContentPanel} this
54445 * @param {Number} width The width after any component adjustments
54446 * @param {Number} height The height after any component adjustments
54452 * Fires when this tab is created
54453 * @param {Roo.ContentPanel} this
54463 if(this.autoScroll){
54464 this.resizeEl.setStyle("overflow", "auto");
54466 // fix randome scrolling
54467 this.el.on('scroll', function() {
54468 Roo.log('fix random scolling');
54469 this.scrollTo('top',0);
54472 content = content || this.content;
54474 this.setContent(content);
54476 if(config && config.url){
54477 this.setUrl(this.url, this.params, this.loadOnce);
54482 Roo.ContentPanel.superclass.constructor.call(this);
54484 if (this.view && typeof(this.view.xtype) != 'undefined') {
54485 this.view.el = this.el.appendChild(document.createElement("div"));
54486 this.view = Roo.factory(this.view);
54487 this.view.render && this.view.render(false, '');
54491 this.fireEvent('render', this);
54494 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
54496 setRegion : function(region){
54497 this.region = region;
54499 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
54501 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
54506 * Returns the toolbar for this Panel if one was configured.
54507 * @return {Roo.Toolbar}
54509 getToolbar : function(){
54510 return this.toolbar;
54513 setActiveState : function(active){
54514 this.active = active;
54516 this.fireEvent("deactivate", this);
54518 this.fireEvent("activate", this);
54522 * Updates this panel's element
54523 * @param {String} content The new content
54524 * @param {Boolean} loadScripts (optional) true to look for and process scripts
54526 setContent : function(content, loadScripts){
54527 this.el.update(content, loadScripts);
54530 ignoreResize : function(w, h){
54531 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
54534 this.lastSize = {width: w, height: h};
54539 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
54540 * @return {Roo.UpdateManager} The UpdateManager
54542 getUpdateManager : function(){
54543 return this.el.getUpdateManager();
54546 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
54547 * @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:
54550 url: "your-url.php",
54551 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
54552 callback: yourFunction,
54553 scope: yourObject, //(optional scope)
54556 text: "Loading...",
54561 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
54562 * 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.
54563 * @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}
54564 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
54565 * @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.
54566 * @return {Roo.ContentPanel} this
54569 var um = this.el.getUpdateManager();
54570 um.update.apply(um, arguments);
54576 * 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.
54577 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
54578 * @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)
54579 * @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)
54580 * @return {Roo.UpdateManager} The UpdateManager
54582 setUrl : function(url, params, loadOnce){
54583 if(this.refreshDelegate){
54584 this.removeListener("activate", this.refreshDelegate);
54586 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
54587 this.on("activate", this.refreshDelegate);
54588 return this.el.getUpdateManager();
54591 _handleRefresh : function(url, params, loadOnce){
54592 if(!loadOnce || !this.loaded){
54593 var updater = this.el.getUpdateManager();
54594 updater.update(url, params, this._setLoaded.createDelegate(this));
54598 _setLoaded : function(){
54599 this.loaded = true;
54603 * Returns this panel's id
54606 getId : function(){
54611 * Returns this panel's element - used by regiosn to add.
54612 * @return {Roo.Element}
54614 getEl : function(){
54615 return this.wrapEl || this.el;
54618 adjustForComponents : function(width, height)
54620 //Roo.log('adjustForComponents ');
54621 if(this.resizeEl != this.el){
54622 width -= this.el.getFrameWidth('lr');
54623 height -= this.el.getFrameWidth('tb');
54626 var te = this.toolbar.getEl();
54627 height -= te.getHeight();
54628 te.setWidth(width);
54631 var te = this.footer.getEl();
54632 //Roo.log("footer:" + te.getHeight());
54634 height -= te.getHeight();
54635 te.setWidth(width);
54639 if(this.adjustments){
54640 width += this.adjustments[0];
54641 height += this.adjustments[1];
54643 return {"width": width, "height": height};
54646 setSize : function(width, height){
54647 if(this.fitToFrame && !this.ignoreResize(width, height)){
54648 if(this.fitContainer && this.resizeEl != this.el){
54649 this.el.setSize(width, height);
54651 var size = this.adjustForComponents(width, height);
54652 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
54653 this.fireEvent('resize', this, size.width, size.height);
54658 * Returns this panel's title
54661 getTitle : function(){
54666 * Set this panel's title
54667 * @param {String} title
54669 setTitle : function(title){
54670 this.title = title;
54672 this.region.updatePanelTitle(this, title);
54677 * Returns true is this panel was configured to be closable
54678 * @return {Boolean}
54680 isClosable : function(){
54681 return this.closable;
54684 beforeSlide : function(){
54686 this.resizeEl.clip();
54689 afterSlide : function(){
54691 this.resizeEl.unclip();
54695 * Force a content refresh from the URL specified in the {@link #setUrl} method.
54696 * Will fail silently if the {@link #setUrl} method has not been called.
54697 * This does not activate the panel, just updates its content.
54699 refresh : function(){
54700 if(this.refreshDelegate){
54701 this.loaded = false;
54702 this.refreshDelegate();
54707 * Destroys this panel
54709 destroy : function(){
54710 this.el.removeAllListeners();
54711 var tempEl = document.createElement("span");
54712 tempEl.appendChild(this.el.dom);
54713 tempEl.innerHTML = "";
54719 * form - if the content panel contains a form - this is a reference to it.
54720 * @type {Roo.form.Form}
54724 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
54725 * This contains a reference to it.
54731 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
54741 * @param {Object} cfg Xtype definition of item to add.
54744 addxtype : function(cfg) {
54746 if (cfg.xtype.match(/^Form$/)) {
54749 //if (this.footer) {
54750 // el = this.footer.container.insertSibling(false, 'before');
54752 el = this.el.createChild();
54755 this.form = new Roo.form.Form(cfg);
54758 if ( this.form.allItems.length) {
54759 this.form.render(el.dom);
54763 // should only have one of theses..
54764 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
54765 // views.. should not be just added - used named prop 'view''
54767 cfg.el = this.el.appendChild(document.createElement("div"));
54770 var ret = new Roo.factory(cfg);
54772 ret.render && ret.render(false, ''); // render blank..
54781 * @class Roo.GridPanel
54782 * @extends Roo.ContentPanel
54784 * Create a new GridPanel.
54785 * @param {Roo.grid.Grid} grid The grid for this panel
54786 * @param {String/Object} config A string to set only the panel's title, or a config object
54788 Roo.GridPanel = function(grid, config){
54791 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
54792 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
54794 this.wrapper.dom.appendChild(grid.getGridEl().dom);
54796 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
54799 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
54801 // xtype created footer. - not sure if will work as we normally have to render first..
54802 if (this.footer && !this.footer.el && this.footer.xtype) {
54804 this.footer.container = this.grid.getView().getFooterPanel(true);
54805 this.footer.dataSource = this.grid.dataSource;
54806 this.footer = Roo.factory(this.footer, Roo);
54810 grid.monitorWindowResize = false; // turn off autosizing
54811 grid.autoHeight = false;
54812 grid.autoWidth = false;
54814 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
54817 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
54818 getId : function(){
54819 return this.grid.id;
54823 * Returns the grid for this panel
54824 * @return {Roo.grid.Grid}
54826 getGrid : function(){
54830 setSize : function(width, height){
54831 if(!this.ignoreResize(width, height)){
54832 var grid = this.grid;
54833 var size = this.adjustForComponents(width, height);
54834 grid.getGridEl().setSize(size.width, size.height);
54839 beforeSlide : function(){
54840 this.grid.getView().scroller.clip();
54843 afterSlide : function(){
54844 this.grid.getView().scroller.unclip();
54847 destroy : function(){
54848 this.grid.destroy();
54850 Roo.GridPanel.superclass.destroy.call(this);
54856 * @class Roo.NestedLayoutPanel
54857 * @extends Roo.ContentPanel
54859 * Create a new NestedLayoutPanel.
54862 * @param {Roo.BorderLayout} layout The layout for this panel
54863 * @param {String/Object} config A string to set only the title or a config object
54865 Roo.NestedLayoutPanel = function(layout, config)
54867 // construct with only one argument..
54868 /* FIXME - implement nicer consturctors
54869 if (layout.layout) {
54871 layout = config.layout;
54872 delete config.layout;
54874 if (layout.xtype && !layout.getEl) {
54875 // then layout needs constructing..
54876 layout = Roo.factory(layout, Roo);
54881 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
54883 layout.monitorWindowResize = false; // turn off autosizing
54884 this.layout = layout;
54885 this.layout.getEl().addClass("x-layout-nested-layout");
54892 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
54894 setSize : function(width, height){
54895 if(!this.ignoreResize(width, height)){
54896 var size = this.adjustForComponents(width, height);
54897 var el = this.layout.getEl();
54898 el.setSize(size.width, size.height);
54899 var touch = el.dom.offsetWidth;
54900 this.layout.layout();
54901 // ie requires a double layout on the first pass
54902 if(Roo.isIE && !this.initialized){
54903 this.initialized = true;
54904 this.layout.layout();
54909 // activate all subpanels if not currently active..
54911 setActiveState : function(active){
54912 this.active = active;
54914 this.fireEvent("deactivate", this);
54918 this.fireEvent("activate", this);
54919 // not sure if this should happen before or after..
54920 if (!this.layout) {
54921 return; // should not happen..
54924 for (var r in this.layout.regions) {
54925 reg = this.layout.getRegion(r);
54926 if (reg.getActivePanel()) {
54927 //reg.showPanel(reg.getActivePanel()); // force it to activate..
54928 reg.setActivePanel(reg.getActivePanel());
54931 if (!reg.panels.length) {
54934 reg.showPanel(reg.getPanel(0));
54943 * Returns the nested BorderLayout for this panel
54944 * @return {Roo.BorderLayout}
54946 getLayout : function(){
54947 return this.layout;
54951 * Adds a xtype elements to the layout of the nested panel
54955 xtype : 'ContentPanel',
54962 xtype : 'NestedLayoutPanel',
54968 items : [ ... list of content panels or nested layout panels.. ]
54972 * @param {Object} cfg Xtype definition of item to add.
54974 addxtype : function(cfg) {
54975 return this.layout.addxtype(cfg);
54980 Roo.ScrollPanel = function(el, config, content){
54981 config = config || {};
54982 config.fitToFrame = true;
54983 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
54985 this.el.dom.style.overflow = "hidden";
54986 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
54987 this.el.removeClass("x-layout-inactive-content");
54988 this.el.on("mousewheel", this.onWheel, this);
54990 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
54991 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
54992 up.unselectable(); down.unselectable();
54993 up.on("click", this.scrollUp, this);
54994 down.on("click", this.scrollDown, this);
54995 up.addClassOnOver("x-scroller-btn-over");
54996 down.addClassOnOver("x-scroller-btn-over");
54997 up.addClassOnClick("x-scroller-btn-click");
54998 down.addClassOnClick("x-scroller-btn-click");
54999 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
55001 this.resizeEl = this.el;
55002 this.el = wrap; this.up = up; this.down = down;
55005 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
55007 wheelIncrement : 5,
55008 scrollUp : function(){
55009 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
55012 scrollDown : function(){
55013 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
55016 afterScroll : function(){
55017 var el = this.resizeEl;
55018 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
55019 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
55020 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
55023 setSize : function(){
55024 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
55025 this.afterScroll();
55028 onWheel : function(e){
55029 var d = e.getWheelDelta();
55030 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
55031 this.afterScroll();
55035 setContent : function(content, loadScripts){
55036 this.resizeEl.update(content, loadScripts);
55050 * @class Roo.TreePanel
55051 * @extends Roo.ContentPanel
55053 * Create a new TreePanel. - defaults to fit/scoll contents.
55054 * @param {String/Object} config A string to set only the panel's title, or a config object
55055 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
55057 Roo.TreePanel = function(config){
55058 var el = config.el;
55059 var tree = config.tree;
55060 delete config.tree;
55061 delete config.el; // hopefull!
55063 // wrapper for IE7 strict & safari scroll issue
55065 var treeEl = el.createChild();
55066 config.resizeEl = treeEl;
55070 Roo.TreePanel.superclass.constructor.call(this, el, config);
55073 this.tree = new Roo.tree.TreePanel(treeEl , tree);
55074 //console.log(tree);
55075 this.on('activate', function()
55077 if (this.tree.rendered) {
55080 //console.log('render tree');
55081 this.tree.render();
55083 // this should not be needed.. - it's actually the 'el' that resizes?
55084 // actuall it breaks the containerScroll - dragging nodes auto scroll at top
55086 //this.on('resize', function (cp, w, h) {
55087 // this.tree.innerCt.setWidth(w);
55088 // this.tree.innerCt.setHeight(h);
55089 // //this.tree.innerCt.setStyle('overflow-y', 'auto');
55096 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
55113 * Ext JS Library 1.1.1
55114 * Copyright(c) 2006-2007, Ext JS, LLC.
55116 * Originally Released Under LGPL - original licence link has changed is not relivant.
55119 * <script type="text/javascript">
55124 * @class Roo.ReaderLayout
55125 * @extends Roo.BorderLayout
55126 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
55127 * center region containing two nested regions (a top one for a list view and one for item preview below),
55128 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
55129 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
55130 * expedites the setup of the overall layout and regions for this common application style.
55133 var reader = new Roo.ReaderLayout();
55134 var CP = Roo.ContentPanel; // shortcut for adding
55136 reader.beginUpdate();
55137 reader.add("north", new CP("north", "North"));
55138 reader.add("west", new CP("west", {title: "West"}));
55139 reader.add("east", new CP("east", {title: "East"}));
55141 reader.regions.listView.add(new CP("listView", "List"));
55142 reader.regions.preview.add(new CP("preview", "Preview"));
55143 reader.endUpdate();
55146 * Create a new ReaderLayout
55147 * @param {Object} config Configuration options
55148 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
55149 * document.body if omitted)
55151 Roo.ReaderLayout = function(config, renderTo){
55152 var c = config || {size:{}};
55153 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
55154 north: c.north !== false ? Roo.apply({
55158 }, c.north) : false,
55159 west: c.west !== false ? Roo.apply({
55167 margins:{left:5,right:0,bottom:5,top:5},
55168 cmargins:{left:5,right:5,bottom:5,top:5}
55169 }, c.west) : false,
55170 east: c.east !== false ? Roo.apply({
55178 margins:{left:0,right:5,bottom:5,top:5},
55179 cmargins:{left:5,right:5,bottom:5,top:5}
55180 }, c.east) : false,
55181 center: Roo.apply({
55182 tabPosition: 'top',
55186 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
55190 this.el.addClass('x-reader');
55192 this.beginUpdate();
55194 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
55195 south: c.preview !== false ? Roo.apply({
55202 cmargins:{top:5,left:0, right:0, bottom:0}
55203 }, c.preview) : false,
55204 center: Roo.apply({
55210 this.add('center', new Roo.NestedLayoutPanel(inner,
55211 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
55215 this.regions.preview = inner.getRegion('south');
55216 this.regions.listView = inner.getRegion('center');
55219 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
55221 * Ext JS Library 1.1.1
55222 * Copyright(c) 2006-2007, Ext JS, LLC.
55224 * Originally Released Under LGPL - original licence link has changed is not relivant.
55227 * <script type="text/javascript">
55231 * @class Roo.grid.Grid
55232 * @extends Roo.util.Observable
55233 * This class represents the primary interface of a component based grid control.
55234 * <br><br>Usage:<pre><code>
55235 var grid = new Roo.grid.Grid("my-container-id", {
55238 selModel: mySelectionModel,
55239 autoSizeColumns: true,
55240 monitorWindowResize: false,
55241 trackMouseOver: true
55246 * <b>Common Problems:</b><br/>
55247 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
55248 * element will correct this<br/>
55249 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
55250 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
55251 * are unpredictable.<br/>
55252 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
55253 * grid to calculate dimensions/offsets.<br/>
55255 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
55256 * The container MUST have some type of size defined for the grid to fill. The container will be
55257 * automatically set to position relative if it isn't already.
55258 * @param {Object} config A config object that sets properties on this grid.
55260 Roo.grid.Grid = function(container, config){
55261 // initialize the container
55262 this.container = Roo.get(container);
55263 this.container.update("");
55264 this.container.setStyle("overflow", "hidden");
55265 this.container.addClass('x-grid-container');
55267 this.id = this.container.id;
55269 Roo.apply(this, config);
55270 // check and correct shorthanded configs
55272 this.dataSource = this.ds;
55276 this.colModel = this.cm;
55280 this.selModel = this.sm;
55284 if (this.selModel) {
55285 this.selModel = Roo.factory(this.selModel, Roo.grid);
55286 this.sm = this.selModel;
55287 this.sm.xmodule = this.xmodule || false;
55289 if (typeof(this.colModel.config) == 'undefined') {
55290 this.colModel = new Roo.grid.ColumnModel(this.colModel);
55291 this.cm = this.colModel;
55292 this.cm.xmodule = this.xmodule || false;
55294 if (this.dataSource) {
55295 this.dataSource= Roo.factory(this.dataSource, Roo.data);
55296 this.ds = this.dataSource;
55297 this.ds.xmodule = this.xmodule || false;
55304 this.container.setWidth(this.width);
55308 this.container.setHeight(this.height);
55315 * The raw click event for the entire grid.
55316 * @param {Roo.EventObject} e
55321 * The raw dblclick event for the entire grid.
55322 * @param {Roo.EventObject} e
55326 * @event contextmenu
55327 * The raw contextmenu event for the entire grid.
55328 * @param {Roo.EventObject} e
55330 "contextmenu" : true,
55333 * The raw mousedown event for the entire grid.
55334 * @param {Roo.EventObject} e
55336 "mousedown" : true,
55339 * The raw mouseup event for the entire grid.
55340 * @param {Roo.EventObject} e
55345 * The raw mouseover event for the entire grid.
55346 * @param {Roo.EventObject} e
55348 "mouseover" : true,
55351 * The raw mouseout event for the entire grid.
55352 * @param {Roo.EventObject} e
55357 * The raw keypress event for the entire grid.
55358 * @param {Roo.EventObject} e
55363 * The raw keydown event for the entire grid.
55364 * @param {Roo.EventObject} e
55372 * Fires when a cell is clicked
55373 * @param {Grid} this
55374 * @param {Number} rowIndex
55375 * @param {Number} columnIndex
55376 * @param {Roo.EventObject} e
55378 "cellclick" : true,
55380 * @event celldblclick
55381 * Fires when a cell is double clicked
55382 * @param {Grid} this
55383 * @param {Number} rowIndex
55384 * @param {Number} columnIndex
55385 * @param {Roo.EventObject} e
55387 "celldblclick" : true,
55390 * Fires when a row is clicked
55391 * @param {Grid} this
55392 * @param {Number} rowIndex
55393 * @param {Roo.EventObject} e
55397 * @event rowdblclick
55398 * Fires when a row is double clicked
55399 * @param {Grid} this
55400 * @param {Number} rowIndex
55401 * @param {Roo.EventObject} e
55403 "rowdblclick" : true,
55405 * @event headerclick
55406 * Fires when a header is clicked
55407 * @param {Grid} this
55408 * @param {Number} columnIndex
55409 * @param {Roo.EventObject} e
55411 "headerclick" : true,
55413 * @event headerdblclick
55414 * Fires when a header cell is double clicked
55415 * @param {Grid} this
55416 * @param {Number} columnIndex
55417 * @param {Roo.EventObject} e
55419 "headerdblclick" : true,
55421 * @event rowcontextmenu
55422 * Fires when a row is right clicked
55423 * @param {Grid} this
55424 * @param {Number} rowIndex
55425 * @param {Roo.EventObject} e
55427 "rowcontextmenu" : true,
55429 * @event cellcontextmenu
55430 * Fires when a cell is right clicked
55431 * @param {Grid} this
55432 * @param {Number} rowIndex
55433 * @param {Number} cellIndex
55434 * @param {Roo.EventObject} e
55436 "cellcontextmenu" : true,
55438 * @event headercontextmenu
55439 * Fires when a header is right clicked
55440 * @param {Grid} this
55441 * @param {Number} columnIndex
55442 * @param {Roo.EventObject} e
55444 "headercontextmenu" : true,
55446 * @event bodyscroll
55447 * Fires when the body element is scrolled
55448 * @param {Number} scrollLeft
55449 * @param {Number} scrollTop
55451 "bodyscroll" : true,
55453 * @event columnresize
55454 * Fires when the user resizes a column
55455 * @param {Number} columnIndex
55456 * @param {Number} newSize
55458 "columnresize" : true,
55460 * @event columnmove
55461 * Fires when the user moves a column
55462 * @param {Number} oldIndex
55463 * @param {Number} newIndex
55465 "columnmove" : true,
55468 * Fires when row(s) start being dragged
55469 * @param {Grid} this
55470 * @param {Roo.GridDD} dd The drag drop object
55471 * @param {event} e The raw browser event
55473 "startdrag" : true,
55476 * Fires when a drag operation is complete
55477 * @param {Grid} this
55478 * @param {Roo.GridDD} dd The drag drop object
55479 * @param {event} e The raw browser event
55484 * Fires when dragged row(s) are dropped on a valid DD target
55485 * @param {Grid} this
55486 * @param {Roo.GridDD} dd The drag drop object
55487 * @param {String} targetId The target drag drop object
55488 * @param {event} e The raw browser event
55493 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
55494 * @param {Grid} this
55495 * @param {Roo.GridDD} dd The drag drop object
55496 * @param {String} targetId The target drag drop object
55497 * @param {event} e The raw browser event
55502 * Fires when the dragged row(s) first cross another DD target while being dragged
55503 * @param {Grid} this
55504 * @param {Roo.GridDD} dd The drag drop object
55505 * @param {String} targetId The target drag drop object
55506 * @param {event} e The raw browser event
55508 "dragenter" : true,
55511 * Fires when the dragged row(s) leave another DD target while being dragged
55512 * @param {Grid} this
55513 * @param {Roo.GridDD} dd The drag drop object
55514 * @param {String} targetId The target drag drop object
55515 * @param {event} e The raw browser event
55520 * Fires when a row is rendered, so you can change add a style to it.
55521 * @param {GridView} gridview The grid view
55522 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
55528 * Fires when the grid is rendered
55529 * @param {Grid} grid
55534 Roo.grid.Grid.superclass.constructor.call(this);
55536 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
55539 * @cfg {String} ddGroup - drag drop group.
55542 * @cfg {String} dragGroup - drag group (?? not sure if needed.)
55546 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
55548 minColumnWidth : 25,
55551 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
55552 * <b>on initial render.</b> It is more efficient to explicitly size the columns
55553 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
55555 autoSizeColumns : false,
55558 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
55560 autoSizeHeaders : true,
55563 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
55565 monitorWindowResize : true,
55568 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
55569 * rows measured to get a columns size. Default is 0 (all rows).
55571 maxRowsToMeasure : 0,
55574 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
55576 trackMouseOver : true,
55579 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
55582 * @cfg {Boolean} enableDrop True to enable drop of elements. Default is false. (double check if this is needed?)
55586 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
55588 enableDragDrop : false,
55591 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
55593 enableColumnMove : true,
55596 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
55598 enableColumnHide : true,
55601 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
55603 enableRowHeightSync : false,
55606 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
55611 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
55613 autoHeight : false,
55616 * @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.
55618 autoExpandColumn : false,
55621 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
55624 autoExpandMin : 50,
55627 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
55629 autoExpandMax : 1000,
55632 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
55637 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
55641 * @cfg {Roo.dd.DropTarget} dropTarget An {@link Roo.dd.DropTarget} config
55651 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
55652 * of a fixed width. Default is false.
55655 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
55660 * @cfg {String} ddText Configures the text is the drag proxy (defaults to "%0 selected row(s)").
55661 * %0 is replaced with the number of selected rows.
55663 ddText : "{0} selected row{1}",
55667 * Called once after all setup has been completed and the grid is ready to be rendered.
55668 * @return {Roo.grid.Grid} this
55670 render : function()
55672 var c = this.container;
55673 // try to detect autoHeight/width mode
55674 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
55675 this.autoHeight = true;
55677 var view = this.getView();
55680 c.on("click", this.onClick, this);
55681 c.on("dblclick", this.onDblClick, this);
55682 c.on("contextmenu", this.onContextMenu, this);
55683 c.on("keydown", this.onKeyDown, this);
55685 c.on("touchstart", this.onTouchStart, this);
55688 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
55690 this.getSelectionModel().init(this);
55695 this.loadMask = new Roo.LoadMask(this.container,
55696 Roo.apply({store:this.dataSource}, this.loadMask));
55700 if (this.toolbar && this.toolbar.xtype) {
55701 this.toolbar.container = this.getView().getHeaderPanel(true);
55702 this.toolbar = new Roo.Toolbar(this.toolbar);
55704 if (this.footer && this.footer.xtype) {
55705 this.footer.dataSource = this.getDataSource();
55706 this.footer.container = this.getView().getFooterPanel(true);
55707 this.footer = Roo.factory(this.footer, Roo);
55709 if (this.dropTarget && this.dropTarget.xtype) {
55710 delete this.dropTarget.xtype;
55711 this.dropTarget = new Roo.dd.DropTarget(this.getView().mainBody, this.dropTarget);
55715 this.rendered = true;
55716 this.fireEvent('render', this);
55721 * Reconfigures the grid to use a different Store and Column Model.
55722 * The View will be bound to the new objects and refreshed.
55723 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
55724 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
55726 reconfigure : function(dataSource, colModel){
55728 this.loadMask.destroy();
55729 this.loadMask = new Roo.LoadMask(this.container,
55730 Roo.apply({store:dataSource}, this.loadMask));
55732 this.view.bind(dataSource, colModel);
55733 this.dataSource = dataSource;
55734 this.colModel = colModel;
55735 this.view.refresh(true);
55739 * Add's a column, default at the end..
55741 * @param {int} position to add (default end)
55742 * @param {Array} of objects of column configuration see {@link Roo.grid.ColumnModel}
55744 addColumns : function(pos, ar)
55747 for (var i =0;i< ar.length;i++) {
55749 cfg.id = typeof(cfg.id) == 'undefined' ? Roo.id() : cfg.id; // don't normally use this..
55750 this.cm.lookup[cfg.id] = cfg;
55754 if (typeof(pos) == 'undefined' || pos >= this.cm.config.length) {
55755 pos = this.cm.config.length; //this.cm.config.push(cfg);
55757 pos = Math.max(0,pos);
55760 this.cm.config.splice.apply(this.cm.config, ar);
55764 this.view.generateRules(this.cm);
55765 this.view.refresh(true);
55773 onKeyDown : function(e){
55774 this.fireEvent("keydown", e);
55778 * Destroy this grid.
55779 * @param {Boolean} removeEl True to remove the element
55781 destroy : function(removeEl, keepListeners){
55783 this.loadMask.destroy();
55785 var c = this.container;
55786 c.removeAllListeners();
55787 this.view.destroy();
55788 this.colModel.purgeListeners();
55789 if(!keepListeners){
55790 this.purgeListeners();
55793 if(removeEl === true){
55799 processEvent : function(name, e){
55800 // does this fire select???
55801 //Roo.log('grid:processEvent ' + name);
55803 if (name != 'touchstart' ) {
55804 this.fireEvent(name, e);
55807 var t = e.getTarget();
55809 var header = v.findHeaderIndex(t);
55810 if(header !== false){
55811 var ename = name == 'touchstart' ? 'click' : name;
55813 this.fireEvent("header" + ename, this, header, e);
55815 var row = v.findRowIndex(t);
55816 var cell = v.findCellIndex(t);
55817 if (name == 'touchstart') {
55818 // first touch is always a click.
55819 // hopefull this happens after selection is updated.?
55822 if (typeof(this.selModel.getSelectedCell) != 'undefined') {
55823 var cs = this.selModel.getSelectedCell();
55824 if (row == cs[0] && cell == cs[1]){
55828 if (typeof(this.selModel.getSelections) != 'undefined') {
55829 var cs = this.selModel.getSelections();
55830 var ds = this.dataSource;
55831 if (cs.length == 1 && ds.getAt(row) == cs[0]){
55842 this.fireEvent("row" + name, this, row, e);
55843 if(cell !== false){
55844 this.fireEvent("cell" + name, this, row, cell, e);
55851 onClick : function(e){
55852 this.processEvent("click", e);
55855 onTouchStart : function(e){
55856 this.processEvent("touchstart", e);
55860 onContextMenu : function(e, t){
55861 this.processEvent("contextmenu", e);
55865 onDblClick : function(e){
55866 this.processEvent("dblclick", e);
55870 walkCells : function(row, col, step, fn, scope){
55871 var cm = this.colModel, clen = cm.getColumnCount();
55872 var ds = this.dataSource, rlen = ds.getCount(), first = true;
55884 if(fn.call(scope || this, row, col, cm) === true){
55902 if(fn.call(scope || this, row, col, cm) === true){
55914 getSelections : function(){
55915 return this.selModel.getSelections();
55919 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
55920 * but if manual update is required this method will initiate it.
55922 autoSize : function(){
55924 this.view.layout();
55925 if(this.view.adjustForScroll){
55926 this.view.adjustForScroll();
55932 * Returns the grid's underlying element.
55933 * @return {Element} The element
55935 getGridEl : function(){
55936 return this.container;
55939 // private for compatibility, overridden by editor grid
55940 stopEditing : function(){},
55943 * Returns the grid's SelectionModel.
55944 * @return {SelectionModel}
55946 getSelectionModel : function(){
55947 if(!this.selModel){
55948 this.selModel = new Roo.grid.RowSelectionModel();
55950 return this.selModel;
55954 * Returns the grid's DataSource.
55955 * @return {DataSource}
55957 getDataSource : function(){
55958 return this.dataSource;
55962 * Returns the grid's ColumnModel.
55963 * @return {ColumnModel}
55965 getColumnModel : function(){
55966 return this.colModel;
55970 * Returns the grid's GridView object.
55971 * @return {GridView}
55973 getView : function(){
55975 this.view = new Roo.grid.GridView(this.viewConfig);
55976 this.relayEvents(this.view, [
55977 "beforerowremoved", "beforerowsinserted",
55978 "beforerefresh", "rowremoved",
55979 "rowsinserted", "rowupdated" ,"refresh"
55985 * Called to get grid's drag proxy text, by default returns this.ddText.
55986 * Override this to put something different in the dragged text.
55989 getDragDropText : function(){
55990 var count = this.selModel.getCount();
55991 return String.format(this.ddText, count, count == 1 ? '' : 's');
55996 * Ext JS Library 1.1.1
55997 * Copyright(c) 2006-2007, Ext JS, LLC.
55999 * Originally Released Under LGPL - original licence link has changed is not relivant.
56002 * <script type="text/javascript">
56005 Roo.grid.AbstractGridView = function(){
56009 "beforerowremoved" : true,
56010 "beforerowsinserted" : true,
56011 "beforerefresh" : true,
56012 "rowremoved" : true,
56013 "rowsinserted" : true,
56014 "rowupdated" : true,
56017 Roo.grid.AbstractGridView.superclass.constructor.call(this);
56020 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
56021 rowClass : "x-grid-row",
56022 cellClass : "x-grid-cell",
56023 tdClass : "x-grid-td",
56024 hdClass : "x-grid-hd",
56025 splitClass : "x-grid-hd-split",
56027 init: function(grid){
56029 var cid = this.grid.getGridEl().id;
56030 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
56031 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
56032 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
56033 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
56036 getColumnRenderers : function(){
56037 var renderers = [];
56038 var cm = this.grid.colModel;
56039 var colCount = cm.getColumnCount();
56040 for(var i = 0; i < colCount; i++){
56041 renderers[i] = cm.getRenderer(i);
56046 getColumnIds : function(){
56048 var cm = this.grid.colModel;
56049 var colCount = cm.getColumnCount();
56050 for(var i = 0; i < colCount; i++){
56051 ids[i] = cm.getColumnId(i);
56056 getDataIndexes : function(){
56057 if(!this.indexMap){
56058 this.indexMap = this.buildIndexMap();
56060 return this.indexMap.colToData;
56063 getColumnIndexByDataIndex : function(dataIndex){
56064 if(!this.indexMap){
56065 this.indexMap = this.buildIndexMap();
56067 return this.indexMap.dataToCol[dataIndex];
56071 * Set a css style for a column dynamically.
56072 * @param {Number} colIndex The index of the column
56073 * @param {String} name The css property name
56074 * @param {String} value The css value
56076 setCSSStyle : function(colIndex, name, value){
56077 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
56078 Roo.util.CSS.updateRule(selector, name, value);
56081 generateRules : function(cm){
56082 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
56083 Roo.util.CSS.removeStyleSheet(rulesId);
56084 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
56085 var cid = cm.getColumnId(i);
56086 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
56087 this.tdSelector, cid, " {\n}\n",
56088 this.hdSelector, cid, " {\n}\n",
56089 this.splitSelector, cid, " {\n}\n");
56091 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
56095 * Ext JS Library 1.1.1
56096 * Copyright(c) 2006-2007, Ext JS, LLC.
56098 * Originally Released Under LGPL - original licence link has changed is not relivant.
56101 * <script type="text/javascript">
56105 // This is a support class used internally by the Grid components
56106 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
56108 this.view = grid.getView();
56109 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
56110 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
56112 this.setHandleElId(Roo.id(hd));
56113 this.setOuterHandleElId(Roo.id(hd2));
56115 this.scroll = false;
56117 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
56119 getDragData : function(e){
56120 var t = Roo.lib.Event.getTarget(e);
56121 var h = this.view.findHeaderCell(t);
56123 return {ddel: h.firstChild, header:h};
56128 onInitDrag : function(e){
56129 this.view.headersDisabled = true;
56130 var clone = this.dragData.ddel.cloneNode(true);
56131 clone.id = Roo.id();
56132 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
56133 this.proxy.update(clone);
56137 afterValidDrop : function(){
56139 setTimeout(function(){
56140 v.headersDisabled = false;
56144 afterInvalidDrop : function(){
56146 setTimeout(function(){
56147 v.headersDisabled = false;
56153 * Ext JS Library 1.1.1
56154 * Copyright(c) 2006-2007, Ext JS, LLC.
56156 * Originally Released Under LGPL - original licence link has changed is not relivant.
56159 * <script type="text/javascript">
56162 // This is a support class used internally by the Grid components
56163 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
56165 this.view = grid.getView();
56166 // split the proxies so they don't interfere with mouse events
56167 this.proxyTop = Roo.DomHelper.append(document.body, {
56168 cls:"col-move-top", html:" "
56170 this.proxyBottom = Roo.DomHelper.append(document.body, {
56171 cls:"col-move-bottom", html:" "
56173 this.proxyTop.hide = this.proxyBottom.hide = function(){
56174 this.setLeftTop(-100,-100);
56175 this.setStyle("visibility", "hidden");
56177 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
56178 // temporarily disabled
56179 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
56180 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
56182 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
56183 proxyOffsets : [-4, -9],
56184 fly: Roo.Element.fly,
56186 getTargetFromEvent : function(e){
56187 var t = Roo.lib.Event.getTarget(e);
56188 var cindex = this.view.findCellIndex(t);
56189 if(cindex !== false){
56190 return this.view.getHeaderCell(cindex);
56195 nextVisible : function(h){
56196 var v = this.view, cm = this.grid.colModel;
56199 if(!cm.isHidden(v.getCellIndex(h))){
56207 prevVisible : function(h){
56208 var v = this.view, cm = this.grid.colModel;
56211 if(!cm.isHidden(v.getCellIndex(h))){
56219 positionIndicator : function(h, n, e){
56220 var x = Roo.lib.Event.getPageX(e);
56221 var r = Roo.lib.Dom.getRegion(n.firstChild);
56222 var px, pt, py = r.top + this.proxyOffsets[1];
56223 if((r.right - x) <= (r.right-r.left)/2){
56224 px = r.right+this.view.borderWidth;
56230 var oldIndex = this.view.getCellIndex(h);
56231 var newIndex = this.view.getCellIndex(n);
56233 if(this.grid.colModel.isFixed(newIndex)){
56237 var locked = this.grid.colModel.isLocked(newIndex);
56242 if(oldIndex < newIndex){
56245 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
56248 px += this.proxyOffsets[0];
56249 this.proxyTop.setLeftTop(px, py);
56250 this.proxyTop.show();
56251 if(!this.bottomOffset){
56252 this.bottomOffset = this.view.mainHd.getHeight();
56254 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
56255 this.proxyBottom.show();
56259 onNodeEnter : function(n, dd, e, data){
56260 if(data.header != n){
56261 this.positionIndicator(data.header, n, e);
56265 onNodeOver : function(n, dd, e, data){
56266 var result = false;
56267 if(data.header != n){
56268 result = this.positionIndicator(data.header, n, e);
56271 this.proxyTop.hide();
56272 this.proxyBottom.hide();
56274 return result ? this.dropAllowed : this.dropNotAllowed;
56277 onNodeOut : function(n, dd, e, data){
56278 this.proxyTop.hide();
56279 this.proxyBottom.hide();
56282 onNodeDrop : function(n, dd, e, data){
56283 var h = data.header;
56285 var cm = this.grid.colModel;
56286 var x = Roo.lib.Event.getPageX(e);
56287 var r = Roo.lib.Dom.getRegion(n.firstChild);
56288 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
56289 var oldIndex = this.view.getCellIndex(h);
56290 var newIndex = this.view.getCellIndex(n);
56291 var locked = cm.isLocked(newIndex);
56295 if(oldIndex < newIndex){
56298 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
56301 cm.setLocked(oldIndex, locked, true);
56302 cm.moveColumn(oldIndex, newIndex);
56303 this.grid.fireEvent("columnmove", oldIndex, newIndex);
56311 * Ext JS Library 1.1.1
56312 * Copyright(c) 2006-2007, Ext JS, LLC.
56314 * Originally Released Under LGPL - original licence link has changed is not relivant.
56317 * <script type="text/javascript">
56321 * @class Roo.grid.GridView
56322 * @extends Roo.util.Observable
56325 * @param {Object} config
56327 Roo.grid.GridView = function(config){
56328 Roo.grid.GridView.superclass.constructor.call(this);
56331 Roo.apply(this, config);
56334 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
56336 unselectable : 'unselectable="on"',
56337 unselectableCls : 'x-unselectable',
56340 rowClass : "x-grid-row",
56342 cellClass : "x-grid-col",
56344 tdClass : "x-grid-td",
56346 hdClass : "x-grid-hd",
56348 splitClass : "x-grid-split",
56350 sortClasses : ["sort-asc", "sort-desc"],
56352 enableMoveAnim : false,
56356 dh : Roo.DomHelper,
56358 fly : Roo.Element.fly,
56360 css : Roo.util.CSS,
56366 scrollIncrement : 22,
56368 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
56370 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
56372 bind : function(ds, cm){
56374 this.ds.un("load", this.onLoad, this);
56375 this.ds.un("datachanged", this.onDataChange, this);
56376 this.ds.un("add", this.onAdd, this);
56377 this.ds.un("remove", this.onRemove, this);
56378 this.ds.un("update", this.onUpdate, this);
56379 this.ds.un("clear", this.onClear, this);
56382 ds.on("load", this.onLoad, this);
56383 ds.on("datachanged", this.onDataChange, this);
56384 ds.on("add", this.onAdd, this);
56385 ds.on("remove", this.onRemove, this);
56386 ds.on("update", this.onUpdate, this);
56387 ds.on("clear", this.onClear, this);
56392 this.cm.un("widthchange", this.onColWidthChange, this);
56393 this.cm.un("headerchange", this.onHeaderChange, this);
56394 this.cm.un("hiddenchange", this.onHiddenChange, this);
56395 this.cm.un("columnmoved", this.onColumnMove, this);
56396 this.cm.un("columnlockchange", this.onColumnLock, this);
56399 this.generateRules(cm);
56400 cm.on("widthchange", this.onColWidthChange, this);
56401 cm.on("headerchange", this.onHeaderChange, this);
56402 cm.on("hiddenchange", this.onHiddenChange, this);
56403 cm.on("columnmoved", this.onColumnMove, this);
56404 cm.on("columnlockchange", this.onColumnLock, this);
56409 init: function(grid){
56410 Roo.grid.GridView.superclass.init.call(this, grid);
56412 this.bind(grid.dataSource, grid.colModel);
56414 grid.on("headerclick", this.handleHeaderClick, this);
56416 if(grid.trackMouseOver){
56417 grid.on("mouseover", this.onRowOver, this);
56418 grid.on("mouseout", this.onRowOut, this);
56420 grid.cancelTextSelection = function(){};
56421 this.gridId = grid.id;
56423 var tpls = this.templates || {};
56426 tpls.master = new Roo.Template(
56427 '<div class="x-grid" hidefocus="true">',
56428 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
56429 '<div class="x-grid-topbar"></div>',
56430 '<div class="x-grid-scroller"><div></div></div>',
56431 '<div class="x-grid-locked">',
56432 '<div class="x-grid-header">{lockedHeader}</div>',
56433 '<div class="x-grid-body">{lockedBody}</div>',
56435 '<div class="x-grid-viewport">',
56436 '<div class="x-grid-header">{header}</div>',
56437 '<div class="x-grid-body">{body}</div>',
56439 '<div class="x-grid-bottombar"></div>',
56441 '<div class="x-grid-resize-proxy"> </div>',
56444 tpls.master.disableformats = true;
56448 tpls.header = new Roo.Template(
56449 '<table border="0" cellspacing="0" cellpadding="0">',
56450 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
56453 tpls.header.disableformats = true;
56455 tpls.header.compile();
56458 tpls.hcell = new Roo.Template(
56459 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
56460 '<div class="x-grid-hd-text ' + this.unselectableCls + '" ' + this.unselectable +'>{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
56463 tpls.hcell.disableFormats = true;
56465 tpls.hcell.compile();
56468 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style} ' +
56469 this.unselectableCls + '" ' + this.unselectable +'> </div>');
56470 tpls.hsplit.disableFormats = true;
56472 tpls.hsplit.compile();
56475 tpls.body = new Roo.Template(
56476 '<table border="0" cellspacing="0" cellpadding="0">',
56477 "<tbody>{rows}</tbody>",
56480 tpls.body.disableFormats = true;
56482 tpls.body.compile();
56485 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
56486 tpls.row.disableFormats = true;
56488 tpls.row.compile();
56491 tpls.cell = new Roo.Template(
56492 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
56493 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text ' +
56494 this.unselectableCls + '" ' + this.unselectable +'" {attr}>{value}</div></div>',
56497 tpls.cell.disableFormats = true;
56499 tpls.cell.compile();
56501 this.templates = tpls;
56504 // remap these for backwards compat
56505 onColWidthChange : function(){
56506 this.updateColumns.apply(this, arguments);
56508 onHeaderChange : function(){
56509 this.updateHeaders.apply(this, arguments);
56511 onHiddenChange : function(){
56512 this.handleHiddenChange.apply(this, arguments);
56514 onColumnMove : function(){
56515 this.handleColumnMove.apply(this, arguments);
56517 onColumnLock : function(){
56518 this.handleLockChange.apply(this, arguments);
56521 onDataChange : function(){
56523 this.updateHeaderSortState();
56526 onClear : function(){
56530 onUpdate : function(ds, record){
56531 this.refreshRow(record);
56534 refreshRow : function(record){
56535 var ds = this.ds, index;
56536 if(typeof record == 'number'){
56538 record = ds.getAt(index);
56540 index = ds.indexOf(record);
56542 this.insertRows(ds, index, index, true);
56543 this.onRemove(ds, record, index+1, true);
56544 this.syncRowHeights(index, index);
56546 this.fireEvent("rowupdated", this, index, record);
56549 onAdd : function(ds, records, index){
56550 this.insertRows(ds, index, index + (records.length-1));
56553 onRemove : function(ds, record, index, isUpdate){
56554 if(isUpdate !== true){
56555 this.fireEvent("beforerowremoved", this, index, record);
56557 var bt = this.getBodyTable(), lt = this.getLockedTable();
56558 if(bt.rows[index]){
56559 bt.firstChild.removeChild(bt.rows[index]);
56561 if(lt.rows[index]){
56562 lt.firstChild.removeChild(lt.rows[index]);
56564 if(isUpdate !== true){
56565 this.stripeRows(index);
56566 this.syncRowHeights(index, index);
56568 this.fireEvent("rowremoved", this, index, record);
56572 onLoad : function(){
56573 this.scrollToTop();
56577 * Scrolls the grid to the top
56579 scrollToTop : function(){
56581 this.scroller.dom.scrollTop = 0;
56587 * Gets a panel in the header of the grid that can be used for toolbars etc.
56588 * After modifying the contents of this panel a call to grid.autoSize() may be
56589 * required to register any changes in size.
56590 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
56591 * @return Roo.Element
56593 getHeaderPanel : function(doShow){
56595 this.headerPanel.show();
56597 return this.headerPanel;
56601 * Gets a panel in the footer of the grid that can be used for toolbars etc.
56602 * After modifying the contents of this panel a call to grid.autoSize() may be
56603 * required to register any changes in size.
56604 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
56605 * @return Roo.Element
56607 getFooterPanel : function(doShow){
56609 this.footerPanel.show();
56611 return this.footerPanel;
56614 initElements : function(){
56615 var E = Roo.Element;
56616 var el = this.grid.getGridEl().dom.firstChild;
56617 var cs = el.childNodes;
56619 this.el = new E(el);
56621 this.focusEl = new E(el.firstChild);
56622 this.focusEl.swallowEvent("click", true);
56624 this.headerPanel = new E(cs[1]);
56625 this.headerPanel.enableDisplayMode("block");
56627 this.scroller = new E(cs[2]);
56628 this.scrollSizer = new E(this.scroller.dom.firstChild);
56630 this.lockedWrap = new E(cs[3]);
56631 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
56632 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
56634 this.mainWrap = new E(cs[4]);
56635 this.mainHd = new E(this.mainWrap.dom.firstChild);
56636 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
56638 this.footerPanel = new E(cs[5]);
56639 this.footerPanel.enableDisplayMode("block");
56641 this.resizeProxy = new E(cs[6]);
56643 this.headerSelector = String.format(
56644 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
56645 this.lockedHd.id, this.mainHd.id
56648 this.splitterSelector = String.format(
56649 '#{0} div.x-grid-split, #{1} div.x-grid-split',
56650 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
56653 idToCssName : function(s)
56655 return s.replace(/[^a-z0-9]+/ig, '-');
56658 getHeaderCell : function(index){
56659 return Roo.DomQuery.select(this.headerSelector)[index];
56662 getHeaderCellMeasure : function(index){
56663 return this.getHeaderCell(index).firstChild;
56666 getHeaderCellText : function(index){
56667 return this.getHeaderCell(index).firstChild.firstChild;
56670 getLockedTable : function(){
56671 return this.lockedBody.dom.firstChild;
56674 getBodyTable : function(){
56675 return this.mainBody.dom.firstChild;
56678 getLockedRow : function(index){
56679 return this.getLockedTable().rows[index];
56682 getRow : function(index){
56683 return this.getBodyTable().rows[index];
56686 getRowComposite : function(index){
56688 this.rowEl = new Roo.CompositeElementLite();
56690 var els = [], lrow, mrow;
56691 if(lrow = this.getLockedRow(index)){
56694 if(mrow = this.getRow(index)){
56697 this.rowEl.elements = els;
56701 * Gets the 'td' of the cell
56703 * @param {Integer} rowIndex row to select
56704 * @param {Integer} colIndex column to select
56708 getCell : function(rowIndex, colIndex){
56709 var locked = this.cm.getLockedCount();
56711 if(colIndex < locked){
56712 source = this.lockedBody.dom.firstChild;
56714 source = this.mainBody.dom.firstChild;
56715 colIndex -= locked;
56717 return source.rows[rowIndex].childNodes[colIndex];
56720 getCellText : function(rowIndex, colIndex){
56721 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
56724 getCellBox : function(cell){
56725 var b = this.fly(cell).getBox();
56726 if(Roo.isOpera){ // opera fails to report the Y
56727 b.y = cell.offsetTop + this.mainBody.getY();
56732 getCellIndex : function(cell){
56733 var id = String(cell.className).match(this.cellRE);
56735 return parseInt(id[1], 10);
56740 findHeaderIndex : function(n){
56741 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
56742 return r ? this.getCellIndex(r) : false;
56745 findHeaderCell : function(n){
56746 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
56747 return r ? r : false;
56750 findRowIndex : function(n){
56754 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
56755 return r ? r.rowIndex : false;
56758 findCellIndex : function(node){
56759 var stop = this.el.dom;
56760 while(node && node != stop){
56761 if(this.findRE.test(node.className)){
56762 return this.getCellIndex(node);
56764 node = node.parentNode;
56769 getColumnId : function(index){
56770 return this.cm.getColumnId(index);
56773 getSplitters : function()
56775 if(this.splitterSelector){
56776 return Roo.DomQuery.select(this.splitterSelector);
56782 getSplitter : function(index){
56783 return this.getSplitters()[index];
56786 onRowOver : function(e, t){
56788 if((row = this.findRowIndex(t)) !== false){
56789 this.getRowComposite(row).addClass("x-grid-row-over");
56793 onRowOut : function(e, t){
56795 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
56796 this.getRowComposite(row).removeClass("x-grid-row-over");
56800 renderHeaders : function(){
56802 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
56803 var cb = [], lb = [], sb = [], lsb = [], p = {};
56804 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
56805 p.cellId = "x-grid-hd-0-" + i;
56806 p.splitId = "x-grid-csplit-0-" + i;
56807 p.id = cm.getColumnId(i);
56808 p.value = cm.getColumnHeader(i) || "";
56809 p.title = cm.getColumnTooltip(i) || (''+p.value).match(/\</) ? '' : p.value || "";
56810 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
56811 if(!cm.isLocked(i)){
56812 cb[cb.length] = ct.apply(p);
56813 sb[sb.length] = st.apply(p);
56815 lb[lb.length] = ct.apply(p);
56816 lsb[lsb.length] = st.apply(p);
56819 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
56820 ht.apply({cells: cb.join(""), splits:sb.join("")})];
56823 updateHeaders : function(){
56824 var html = this.renderHeaders();
56825 this.lockedHd.update(html[0]);
56826 this.mainHd.update(html[1]);
56830 * Focuses the specified row.
56831 * @param {Number} row The row index
56833 focusRow : function(row)
56835 //Roo.log('GridView.focusRow');
56836 var x = this.scroller.dom.scrollLeft;
56837 this.focusCell(row, 0, false);
56838 this.scroller.dom.scrollLeft = x;
56842 * Focuses the specified cell.
56843 * @param {Number} row The row index
56844 * @param {Number} col The column index
56845 * @param {Boolean} hscroll false to disable horizontal scrolling
56847 focusCell : function(row, col, hscroll)
56849 //Roo.log('GridView.focusCell');
56850 var el = this.ensureVisible(row, col, hscroll);
56851 this.focusEl.alignTo(el, "tl-tl");
56853 this.focusEl.focus();
56855 this.focusEl.focus.defer(1, this.focusEl);
56860 * Scrolls the specified cell into view
56861 * @param {Number} row The row index
56862 * @param {Number} col The column index
56863 * @param {Boolean} hscroll false to disable horizontal scrolling
56865 ensureVisible : function(row, col, hscroll)
56867 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
56868 //return null; //disable for testing.
56869 if(typeof row != "number"){
56870 row = row.rowIndex;
56872 if(row < 0 && row >= this.ds.getCount()){
56875 col = (col !== undefined ? col : 0);
56876 var cm = this.grid.colModel;
56877 while(cm.isHidden(col)){
56881 var el = this.getCell(row, col);
56885 var c = this.scroller.dom;
56887 var ctop = parseInt(el.offsetTop, 10);
56888 var cleft = parseInt(el.offsetLeft, 10);
56889 var cbot = ctop + el.offsetHeight;
56890 var cright = cleft + el.offsetWidth;
56892 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
56893 var stop = parseInt(c.scrollTop, 10);
56894 var sleft = parseInt(c.scrollLeft, 10);
56895 var sbot = stop + ch;
56896 var sright = sleft + c.clientWidth;
56898 Roo.log('GridView.ensureVisible:' +
56900 ' c.clientHeight:' + c.clientHeight +
56901 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
56909 c.scrollTop = ctop;
56910 //Roo.log("set scrolltop to ctop DISABLE?");
56911 }else if(cbot > sbot){
56912 //Roo.log("set scrolltop to cbot-ch");
56913 c.scrollTop = cbot-ch;
56916 if(hscroll !== false){
56918 c.scrollLeft = cleft;
56919 }else if(cright > sright){
56920 c.scrollLeft = cright-c.clientWidth;
56927 updateColumns : function(){
56928 this.grid.stopEditing();
56929 var cm = this.grid.colModel, colIds = this.getColumnIds();
56930 //var totalWidth = cm.getTotalWidth();
56932 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
56933 //if(cm.isHidden(i)) continue;
56934 var w = cm.getColumnWidth(i);
56935 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
56936 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
56938 this.updateSplitters();
56941 generateRules : function(cm){
56942 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
56943 Roo.util.CSS.removeStyleSheet(rulesId);
56944 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
56945 var cid = cm.getColumnId(i);
56947 if(cm.config[i].align){
56948 align = 'text-align:'+cm.config[i].align+';';
56951 if(cm.isHidden(i)){
56952 hidden = 'display:none;';
56954 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
56956 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
56957 this.hdSelector, cid, " {\n", align, width, "}\n",
56958 this.tdSelector, cid, " {\n",hidden,"\n}\n",
56959 this.splitSelector, cid, " {\n", hidden , "\n}\n");
56961 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
56964 updateSplitters : function(){
56965 var cm = this.cm, s = this.getSplitters();
56966 if(s){ // splitters not created yet
56967 var pos = 0, locked = true;
56968 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
56969 if(cm.isHidden(i)) {
56972 var w = cm.getColumnWidth(i); // make sure it's a number
56973 if(!cm.isLocked(i) && locked){
56978 s[i].style.left = (pos-this.splitOffset) + "px";
56983 handleHiddenChange : function(colModel, colIndex, hidden){
56985 this.hideColumn(colIndex);
56987 this.unhideColumn(colIndex);
56991 hideColumn : function(colIndex){
56992 var cid = this.getColumnId(colIndex);
56993 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
56994 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
56996 this.updateHeaders();
56998 this.updateSplitters();
57002 unhideColumn : function(colIndex){
57003 var cid = this.getColumnId(colIndex);
57004 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
57005 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
57008 this.updateHeaders();
57010 this.updateSplitters();
57014 insertRows : function(dm, firstRow, lastRow, isUpdate){
57015 if(firstRow == 0 && lastRow == dm.getCount()-1){
57019 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
57021 var s = this.getScrollState();
57022 var markup = this.renderRows(firstRow, lastRow);
57023 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
57024 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
57025 this.restoreScroll(s);
57027 this.fireEvent("rowsinserted", this, firstRow, lastRow);
57028 this.syncRowHeights(firstRow, lastRow);
57029 this.stripeRows(firstRow);
57035 bufferRows : function(markup, target, index){
57036 var before = null, trows = target.rows, tbody = target.tBodies[0];
57037 if(index < trows.length){
57038 before = trows[index];
57040 var b = document.createElement("div");
57041 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
57042 var rows = b.firstChild.rows;
57043 for(var i = 0, len = rows.length; i < len; i++){
57045 tbody.insertBefore(rows[0], before);
57047 tbody.appendChild(rows[0]);
57054 deleteRows : function(dm, firstRow, lastRow){
57055 if(dm.getRowCount()<1){
57056 this.fireEvent("beforerefresh", this);
57057 this.mainBody.update("");
57058 this.lockedBody.update("");
57059 this.fireEvent("refresh", this);
57061 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
57062 var bt = this.getBodyTable();
57063 var tbody = bt.firstChild;
57064 var rows = bt.rows;
57065 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
57066 tbody.removeChild(rows[firstRow]);
57068 this.stripeRows(firstRow);
57069 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
57073 updateRows : function(dataSource, firstRow, lastRow){
57074 var s = this.getScrollState();
57076 this.restoreScroll(s);
57079 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
57083 this.updateHeaderSortState();
57086 getScrollState : function(){
57088 var sb = this.scroller.dom;
57089 return {left: sb.scrollLeft, top: sb.scrollTop};
57092 stripeRows : function(startRow){
57093 if(!this.grid.stripeRows || this.ds.getCount() < 1){
57096 startRow = startRow || 0;
57097 var rows = this.getBodyTable().rows;
57098 var lrows = this.getLockedTable().rows;
57099 var cls = ' x-grid-row-alt ';
57100 for(var i = startRow, len = rows.length; i < len; i++){
57101 var row = rows[i], lrow = lrows[i];
57102 var isAlt = ((i+1) % 2 == 0);
57103 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
57104 if(isAlt == hasAlt){
57108 row.className += " x-grid-row-alt";
57110 row.className = row.className.replace("x-grid-row-alt", "");
57113 lrow.className = row.className;
57118 restoreScroll : function(state){
57119 //Roo.log('GridView.restoreScroll');
57120 var sb = this.scroller.dom;
57121 sb.scrollLeft = state.left;
57122 sb.scrollTop = state.top;
57126 syncScroll : function(){
57127 //Roo.log('GridView.syncScroll');
57128 var sb = this.scroller.dom;
57129 var sh = this.mainHd.dom;
57130 var bs = this.mainBody.dom;
57131 var lv = this.lockedBody.dom;
57132 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
57133 lv.scrollTop = bs.scrollTop = sb.scrollTop;
57136 handleScroll : function(e){
57138 var sb = this.scroller.dom;
57139 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
57143 handleWheel : function(e){
57144 var d = e.getWheelDelta();
57145 this.scroller.dom.scrollTop -= d*22;
57146 // set this here to prevent jumpy scrolling on large tables
57147 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
57151 renderRows : function(startRow, endRow){
57152 // pull in all the crap needed to render rows
57153 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
57154 var colCount = cm.getColumnCount();
57156 if(ds.getCount() < 1){
57160 // build a map for all the columns
57162 for(var i = 0; i < colCount; i++){
57163 var name = cm.getDataIndex(i);
57165 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
57166 renderer : cm.getRenderer(i),
57167 id : cm.getColumnId(i),
57168 locked : cm.isLocked(i),
57169 has_editor : cm.isCellEditable(i)
57173 startRow = startRow || 0;
57174 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
57176 // records to render
57177 var rs = ds.getRange(startRow, endRow);
57179 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
57182 // As much as I hate to duplicate code, this was branched because FireFox really hates
57183 // [].join("") on strings. The performance difference was substantial enough to
57184 // branch this function
57185 doRender : Roo.isGecko ?
57186 function(cs, rs, ds, startRow, colCount, stripe){
57187 var ts = this.templates, ct = ts.cell, rt = ts.row;
57189 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
57191 var hasListener = this.grid.hasListener('rowclass');
57193 for(var j = 0, len = rs.length; j < len; j++){
57194 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
57195 for(var i = 0; i < colCount; i++){
57197 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
57199 p.css = p.attr = "";
57200 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
57201 if(p.value == undefined || p.value === "") {
57202 p.value = " ";
57205 p.css += ' x-grid-editable-cell';
57207 if(c.dirty && typeof r.modified[c.name] !== 'undefined'){
57208 p.css += ' x-grid-dirty-cell';
57210 var markup = ct.apply(p);
57218 if(stripe && ((rowIndex+1) % 2 == 0)){
57219 alt.push("x-grid-row-alt")
57222 alt.push( " x-grid-dirty-row");
57225 if(this.getRowClass){
57226 alt.push(this.getRowClass(r, rowIndex));
57232 rowIndex : rowIndex,
57235 this.grid.fireEvent('rowclass', this, rowcfg);
57236 alt.push(rowcfg.rowClass);
57238 rp.alt = alt.join(" ");
57239 lbuf+= rt.apply(rp);
57241 buf+= rt.apply(rp);
57243 return [lbuf, buf];
57245 function(cs, rs, ds, startRow, colCount, stripe){
57246 var ts = this.templates, ct = ts.cell, rt = ts.row;
57248 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
57249 var hasListener = this.grid.hasListener('rowclass');
57252 for(var j = 0, len = rs.length; j < len; j++){
57253 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
57254 for(var i = 0; i < colCount; i++){
57256 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
57258 p.css = p.attr = "";
57259 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
57260 if(p.value == undefined || p.value === "") {
57261 p.value = " ";
57265 p.css += ' x-grid-editable-cell';
57267 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
57268 p.css += ' x-grid-dirty-cell'
57271 var markup = ct.apply(p);
57273 cb[cb.length] = markup;
57275 lcb[lcb.length] = markup;
57279 if(stripe && ((rowIndex+1) % 2 == 0)){
57280 alt.push( "x-grid-row-alt");
57283 alt.push(" x-grid-dirty-row");
57286 if(this.getRowClass){
57287 alt.push( this.getRowClass(r, rowIndex));
57293 rowIndex : rowIndex,
57296 this.grid.fireEvent('rowclass', this, rowcfg);
57297 alt.push(rowcfg.rowClass);
57300 rp.alt = alt.join(" ");
57301 rp.cells = lcb.join("");
57302 lbuf[lbuf.length] = rt.apply(rp);
57303 rp.cells = cb.join("");
57304 buf[buf.length] = rt.apply(rp);
57306 return [lbuf.join(""), buf.join("")];
57309 renderBody : function(){
57310 var markup = this.renderRows();
57311 var bt = this.templates.body;
57312 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
57316 * Refreshes the grid
57317 * @param {Boolean} headersToo
57319 refresh : function(headersToo){
57320 this.fireEvent("beforerefresh", this);
57321 this.grid.stopEditing();
57322 var result = this.renderBody();
57323 this.lockedBody.update(result[0]);
57324 this.mainBody.update(result[1]);
57325 if(headersToo === true){
57326 this.updateHeaders();
57327 this.updateColumns();
57328 this.updateSplitters();
57329 this.updateHeaderSortState();
57331 this.syncRowHeights();
57333 this.fireEvent("refresh", this);
57336 handleColumnMove : function(cm, oldIndex, newIndex){
57337 this.indexMap = null;
57338 var s = this.getScrollState();
57339 this.refresh(true);
57340 this.restoreScroll(s);
57341 this.afterMove(newIndex);
57344 afterMove : function(colIndex){
57345 if(this.enableMoveAnim && Roo.enableFx){
57346 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
57348 // if multisort - fix sortOrder, and reload..
57349 if (this.grid.dataSource.multiSort) {
57350 // the we can call sort again..
57351 var dm = this.grid.dataSource;
57352 var cm = this.grid.colModel;
57354 for(var i = 0; i < cm.config.length; i++ ) {
57356 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
57357 continue; // dont' bother, it's not in sort list or being set.
57360 so.push(cm.config[i].dataIndex);
57363 dm.load(dm.lastOptions);
57370 updateCell : function(dm, rowIndex, dataIndex){
57371 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
57372 if(typeof colIndex == "undefined"){ // not present in grid
57375 var cm = this.grid.colModel;
57376 var cell = this.getCell(rowIndex, colIndex);
57377 var cellText = this.getCellText(rowIndex, colIndex);
57380 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
57381 id : cm.getColumnId(colIndex),
57382 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
57384 var renderer = cm.getRenderer(colIndex);
57385 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
57386 if(typeof val == "undefined" || val === "") {
57389 cellText.innerHTML = val;
57390 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
57391 this.syncRowHeights(rowIndex, rowIndex);
57394 calcColumnWidth : function(colIndex, maxRowsToMeasure){
57396 if(this.grid.autoSizeHeaders){
57397 var h = this.getHeaderCellMeasure(colIndex);
57398 maxWidth = Math.max(maxWidth, h.scrollWidth);
57401 if(this.cm.isLocked(colIndex)){
57402 tb = this.getLockedTable();
57405 tb = this.getBodyTable();
57406 index = colIndex - this.cm.getLockedCount();
57409 var rows = tb.rows;
57410 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
57411 for(var i = 0; i < stopIndex; i++){
57412 var cell = rows[i].childNodes[index].firstChild;
57413 maxWidth = Math.max(maxWidth, cell.scrollWidth);
57416 return maxWidth + /*margin for error in IE*/ 5;
57419 * Autofit a column to its content.
57420 * @param {Number} colIndex
57421 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
57423 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
57424 if(this.cm.isHidden(colIndex)){
57425 return; // can't calc a hidden column
57428 var cid = this.cm.getColumnId(colIndex);
57429 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
57430 if(this.grid.autoSizeHeaders){
57431 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
57434 var newWidth = this.calcColumnWidth(colIndex);
57435 this.cm.setColumnWidth(colIndex,
57436 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
57437 if(!suppressEvent){
57438 this.grid.fireEvent("columnresize", colIndex, newWidth);
57443 * Autofits all columns to their content and then expands to fit any extra space in the grid
57445 autoSizeColumns : function(){
57446 var cm = this.grid.colModel;
57447 var colCount = cm.getColumnCount();
57448 for(var i = 0; i < colCount; i++){
57449 this.autoSizeColumn(i, true, true);
57451 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
57454 this.updateColumns();
57460 * Autofits all columns to the grid's width proportionate with their current size
57461 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
57463 fitColumns : function(reserveScrollSpace){
57464 var cm = this.grid.colModel;
57465 var colCount = cm.getColumnCount();
57469 for (i = 0; i < colCount; i++){
57470 if(!cm.isHidden(i) && !cm.isFixed(i)){
57471 w = cm.getColumnWidth(i);
57477 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
57478 if(reserveScrollSpace){
57481 var frac = (avail - cm.getTotalWidth())/width;
57482 while (cols.length){
57485 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
57487 this.updateColumns();
57491 onRowSelect : function(rowIndex){
57492 var row = this.getRowComposite(rowIndex);
57493 row.addClass("x-grid-row-selected");
57496 onRowDeselect : function(rowIndex){
57497 var row = this.getRowComposite(rowIndex);
57498 row.removeClass("x-grid-row-selected");
57501 onCellSelect : function(row, col){
57502 var cell = this.getCell(row, col);
57504 Roo.fly(cell).addClass("x-grid-cell-selected");
57508 onCellDeselect : function(row, col){
57509 var cell = this.getCell(row, col);
57511 Roo.fly(cell).removeClass("x-grid-cell-selected");
57515 updateHeaderSortState : function(){
57517 // sort state can be single { field: xxx, direction : yyy}
57518 // or { xxx=>ASC , yyy : DESC ..... }
57521 if (!this.ds.multiSort) {
57522 var state = this.ds.getSortState();
57526 mstate[state.field] = state.direction;
57527 // FIXME... - this is not used here.. but might be elsewhere..
57528 this.sortState = state;
57531 mstate = this.ds.sortToggle;
57533 //remove existing sort classes..
57535 var sc = this.sortClasses;
57536 var hds = this.el.select(this.headerSelector).removeClass(sc);
57538 for(var f in mstate) {
57540 var sortColumn = this.cm.findColumnIndex(f);
57542 if(sortColumn != -1){
57543 var sortDir = mstate[f];
57544 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
57553 handleHeaderClick : function(g, index,e){
57555 Roo.log("header click");
57558 // touch events on header are handled by context
57559 this.handleHdCtx(g,index,e);
57564 if(this.headersDisabled){
57567 var dm = g.dataSource, cm = g.colModel;
57568 if(!cm.isSortable(index)){
57573 if (dm.multiSort) {
57574 // update the sortOrder
57576 for(var i = 0; i < cm.config.length; i++ ) {
57578 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
57579 continue; // dont' bother, it's not in sort list or being set.
57582 so.push(cm.config[i].dataIndex);
57588 dm.sort(cm.getDataIndex(index));
57592 destroy : function(){
57594 this.colMenu.removeAll();
57595 Roo.menu.MenuMgr.unregister(this.colMenu);
57596 this.colMenu.getEl().remove();
57597 delete this.colMenu;
57600 this.hmenu.removeAll();
57601 Roo.menu.MenuMgr.unregister(this.hmenu);
57602 this.hmenu.getEl().remove();
57605 if(this.grid.enableColumnMove){
57606 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
57608 for(var dd in dds){
57609 if(!dds[dd].config.isTarget && dds[dd].dragElId){
57610 var elid = dds[dd].dragElId;
57612 Roo.get(elid).remove();
57613 } else if(dds[dd].config.isTarget){
57614 dds[dd].proxyTop.remove();
57615 dds[dd].proxyBottom.remove();
57618 if(Roo.dd.DDM.locationCache[dd]){
57619 delete Roo.dd.DDM.locationCache[dd];
57622 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
57625 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
57626 this.bind(null, null);
57627 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
57630 handleLockChange : function(){
57631 this.refresh(true);
57634 onDenyColumnLock : function(){
57638 onDenyColumnHide : function(){
57642 handleHdMenuClick : function(item){
57643 var index = this.hdCtxIndex;
57644 var cm = this.cm, ds = this.ds;
57647 ds.sort(cm.getDataIndex(index), "ASC");
57650 ds.sort(cm.getDataIndex(index), "DESC");
57653 var lc = cm.getLockedCount();
57654 if(cm.getColumnCount(true) <= lc+1){
57655 this.onDenyColumnLock();
57659 cm.setLocked(index, true, true);
57660 cm.moveColumn(index, lc);
57661 this.grid.fireEvent("columnmove", index, lc);
57663 cm.setLocked(index, true);
57667 var lc = cm.getLockedCount();
57668 if((lc-1) != index){
57669 cm.setLocked(index, false, true);
57670 cm.moveColumn(index, lc-1);
57671 this.grid.fireEvent("columnmove", index, lc-1);
57673 cm.setLocked(index, false);
57676 case 'wider': // used to expand cols on touch..
57678 var cw = cm.getColumnWidth(index);
57679 cw += (item.id == 'wider' ? 1 : -1) * 50;
57680 cw = Math.max(0, cw);
57681 cw = Math.min(cw,4000);
57682 cm.setColumnWidth(index, cw);
57686 index = cm.getIndexById(item.id.substr(4));
57688 if(item.checked && cm.getColumnCount(true) <= 1){
57689 this.onDenyColumnHide();
57692 cm.setHidden(index, item.checked);
57698 beforeColMenuShow : function(){
57699 var cm = this.cm, colCount = cm.getColumnCount();
57700 this.colMenu.removeAll();
57701 for(var i = 0; i < colCount; i++){
57702 this.colMenu.add(new Roo.menu.CheckItem({
57703 id: "col-"+cm.getColumnId(i),
57704 text: cm.getColumnHeader(i),
57705 checked: !cm.isHidden(i),
57711 handleHdCtx : function(g, index, e){
57713 var hd = this.getHeaderCell(index);
57714 this.hdCtxIndex = index;
57715 var ms = this.hmenu.items, cm = this.cm;
57716 ms.get("asc").setDisabled(!cm.isSortable(index));
57717 ms.get("desc").setDisabled(!cm.isSortable(index));
57718 if(this.grid.enableColLock !== false){
57719 ms.get("lock").setDisabled(cm.isLocked(index));
57720 ms.get("unlock").setDisabled(!cm.isLocked(index));
57722 this.hmenu.show(hd, "tl-bl");
57725 handleHdOver : function(e){
57726 var hd = this.findHeaderCell(e.getTarget());
57727 if(hd && !this.headersDisabled){
57728 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
57729 this.fly(hd).addClass("x-grid-hd-over");
57734 handleHdOut : function(e){
57735 var hd = this.findHeaderCell(e.getTarget());
57737 this.fly(hd).removeClass("x-grid-hd-over");
57741 handleSplitDblClick : function(e, t){
57742 var i = this.getCellIndex(t);
57743 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
57744 this.autoSizeColumn(i, true);
57749 render : function(){
57752 var colCount = cm.getColumnCount();
57754 if(this.grid.monitorWindowResize === true){
57755 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
57757 var header = this.renderHeaders();
57758 var body = this.templates.body.apply({rows:""});
57759 var html = this.templates.master.apply({
57762 lockedHeader: header[0],
57766 //this.updateColumns();
57768 this.grid.getGridEl().dom.innerHTML = html;
57770 this.initElements();
57772 // a kludge to fix the random scolling effect in webkit
57773 this.el.on("scroll", function() {
57774 this.el.dom.scrollTop=0; // hopefully not recursive..
57777 this.scroller.on("scroll", this.handleScroll, this);
57778 this.lockedBody.on("mousewheel", this.handleWheel, this);
57779 this.mainBody.on("mousewheel", this.handleWheel, this);
57781 this.mainHd.on("mouseover", this.handleHdOver, this);
57782 this.mainHd.on("mouseout", this.handleHdOut, this);
57783 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
57784 {delegate: "."+this.splitClass});
57786 this.lockedHd.on("mouseover", this.handleHdOver, this);
57787 this.lockedHd.on("mouseout", this.handleHdOut, this);
57788 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
57789 {delegate: "."+this.splitClass});
57791 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
57792 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
57795 this.updateSplitters();
57797 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
57798 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
57799 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
57802 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
57803 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
57805 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
57806 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
57808 if(this.grid.enableColLock !== false){
57809 this.hmenu.add('-',
57810 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
57811 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
57815 this.hmenu.add('-',
57816 {id:"wider", text: this.columnsWiderText},
57817 {id:"narrow", text: this.columnsNarrowText }
57823 if(this.grid.enableColumnHide !== false){
57825 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
57826 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
57827 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
57829 this.hmenu.add('-',
57830 {id:"columns", text: this.columnsText, menu: this.colMenu}
57833 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
57835 this.grid.on("headercontextmenu", this.handleHdCtx, this);
57838 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
57839 this.dd = new Roo.grid.GridDragZone(this.grid, {
57840 ddGroup : this.grid.ddGroup || 'GridDD'
57846 for(var i = 0; i < colCount; i++){
57847 if(cm.isHidden(i)){
57848 this.hideColumn(i);
57850 if(cm.config[i].align){
57851 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
57852 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
57856 this.updateHeaderSortState();
57858 this.beforeInitialResize();
57861 // two part rendering gives faster view to the user
57862 this.renderPhase2.defer(1, this);
57865 renderPhase2 : function(){
57866 // render the rows now
57868 if(this.grid.autoSizeColumns){
57869 this.autoSizeColumns();
57873 beforeInitialResize : function(){
57877 onColumnSplitterMoved : function(i, w){
57878 this.userResized = true;
57879 var cm = this.grid.colModel;
57880 cm.setColumnWidth(i, w, true);
57881 var cid = cm.getColumnId(i);
57882 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
57883 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
57884 this.updateSplitters();
57886 this.grid.fireEvent("columnresize", i, w);
57889 syncRowHeights : function(startIndex, endIndex){
57890 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
57891 startIndex = startIndex || 0;
57892 var mrows = this.getBodyTable().rows;
57893 var lrows = this.getLockedTable().rows;
57894 var len = mrows.length-1;
57895 endIndex = Math.min(endIndex || len, len);
57896 for(var i = startIndex; i <= endIndex; i++){
57897 var m = mrows[i], l = lrows[i];
57898 var h = Math.max(m.offsetHeight, l.offsetHeight);
57899 m.style.height = l.style.height = h + "px";
57904 layout : function(initialRender, is2ndPass)
57907 var auto = g.autoHeight;
57908 var scrollOffset = 16;
57909 var c = g.getGridEl(), cm = this.cm,
57910 expandCol = g.autoExpandColumn,
57912 //c.beginMeasure();
57914 if(!c.dom.offsetWidth){ // display:none?
57916 this.lockedWrap.show();
57917 this.mainWrap.show();
57922 var hasLock = this.cm.isLocked(0);
57924 var tbh = this.headerPanel.getHeight();
57925 var bbh = this.footerPanel.getHeight();
57928 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
57929 var newHeight = ch + c.getBorderWidth("tb");
57931 newHeight = Math.min(g.maxHeight, newHeight);
57933 c.setHeight(newHeight);
57937 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
57940 var s = this.scroller;
57942 var csize = c.getSize(true);
57944 this.el.setSize(csize.width, csize.height);
57946 this.headerPanel.setWidth(csize.width);
57947 this.footerPanel.setWidth(csize.width);
57949 var hdHeight = this.mainHd.getHeight();
57950 var vw = csize.width;
57951 var vh = csize.height - (tbh + bbh);
57955 var bt = this.getBodyTable();
57957 if(cm.getLockedCount() == cm.config.length){
57958 bt = this.getLockedTable();
57961 var ltWidth = hasLock ?
57962 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
57964 var scrollHeight = bt.offsetHeight;
57965 var scrollWidth = ltWidth + bt.offsetWidth;
57966 var vscroll = false, hscroll = false;
57968 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
57970 var lw = this.lockedWrap, mw = this.mainWrap;
57971 var lb = this.lockedBody, mb = this.mainBody;
57973 setTimeout(function(){
57974 var t = s.dom.offsetTop;
57975 var w = s.dom.clientWidth,
57976 h = s.dom.clientHeight;
57979 lw.setSize(ltWidth, h);
57981 mw.setLeftTop(ltWidth, t);
57982 mw.setSize(w-ltWidth, h);
57984 lb.setHeight(h-hdHeight);
57985 mb.setHeight(h-hdHeight);
57987 if(is2ndPass !== true && !gv.userResized && expandCol){
57988 // high speed resize without full column calculation
57990 var ci = cm.getIndexById(expandCol);
57992 ci = cm.findColumnIndex(expandCol);
57994 ci = Math.max(0, ci); // make sure it's got at least the first col.
57995 var expandId = cm.getColumnId(ci);
57996 var tw = cm.getTotalWidth(false);
57997 var currentWidth = cm.getColumnWidth(ci);
57998 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
57999 if(currentWidth != cw){
58000 cm.setColumnWidth(ci, cw, true);
58001 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
58002 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
58003 gv.updateSplitters();
58004 gv.layout(false, true);
58016 onWindowResize : function(){
58017 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
58023 appendFooter : function(parentEl){
58027 sortAscText : "Sort Ascending",
58028 sortDescText : "Sort Descending",
58029 lockText : "Lock Column",
58030 unlockText : "Unlock Column",
58031 columnsText : "Columns",
58033 columnsWiderText : "Wider",
58034 columnsNarrowText : "Thinner"
58038 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
58039 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
58040 this.proxy.el.addClass('x-grid3-col-dd');
58043 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
58044 handleMouseDown : function(e){
58048 callHandleMouseDown : function(e){
58049 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
58054 * Ext JS Library 1.1.1
58055 * Copyright(c) 2006-2007, Ext JS, LLC.
58057 * Originally Released Under LGPL - original licence link has changed is not relivant.
58060 * <script type="text/javascript">
58064 // This is a support class used internally by the Grid components
58065 Roo.grid.SplitDragZone = function(grid, hd, hd2){
58067 this.view = grid.getView();
58068 this.proxy = this.view.resizeProxy;
58069 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
58070 "gridSplitters" + this.grid.getGridEl().id, {
58071 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
58073 this.setHandleElId(Roo.id(hd));
58074 this.setOuterHandleElId(Roo.id(hd2));
58075 this.scroll = false;
58077 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
58078 fly: Roo.Element.fly,
58080 b4StartDrag : function(x, y){
58081 this.view.headersDisabled = true;
58082 this.proxy.setHeight(this.view.mainWrap.getHeight());
58083 var w = this.cm.getColumnWidth(this.cellIndex);
58084 var minw = Math.max(w-this.grid.minColumnWidth, 0);
58085 this.resetConstraints();
58086 this.setXConstraint(minw, 1000);
58087 this.setYConstraint(0, 0);
58088 this.minX = x - minw;
58089 this.maxX = x + 1000;
58091 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
58095 handleMouseDown : function(e){
58096 ev = Roo.EventObject.setEvent(e);
58097 var t = this.fly(ev.getTarget());
58098 if(t.hasClass("x-grid-split")){
58099 this.cellIndex = this.view.getCellIndex(t.dom);
58100 this.split = t.dom;
58101 this.cm = this.grid.colModel;
58102 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
58103 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
58108 endDrag : function(e){
58109 this.view.headersDisabled = false;
58110 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
58111 var diff = endX - this.startPos;
58112 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
58115 autoOffset : function(){
58116 this.setDelta(0,0);
58120 * Ext JS Library 1.1.1
58121 * Copyright(c) 2006-2007, Ext JS, LLC.
58123 * Originally Released Under LGPL - original licence link has changed is not relivant.
58126 * <script type="text/javascript">
58130 // This is a support class used internally by the Grid components
58131 Roo.grid.GridDragZone = function(grid, config){
58132 this.view = grid.getView();
58133 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
58134 if(this.view.lockedBody){
58135 this.setHandleElId(Roo.id(this.view.mainBody.dom));
58136 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
58138 this.scroll = false;
58140 this.ddel = document.createElement('div');
58141 this.ddel.className = 'x-grid-dd-wrap';
58144 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
58145 ddGroup : "GridDD",
58147 getDragData : function(e){
58148 var t = Roo.lib.Event.getTarget(e);
58149 var rowIndex = this.view.findRowIndex(t);
58150 var sm = this.grid.selModel;
58152 //Roo.log(rowIndex);
58154 if (sm.getSelectedCell) {
58155 // cell selection..
58156 if (!sm.getSelectedCell()) {
58159 if (rowIndex != sm.getSelectedCell()[0]) {
58164 if (sm.getSelections && sm.getSelections().length < 1) {
58169 // before it used to all dragging of unseleted... - now we dont do that.
58170 if(rowIndex !== false){
58175 //Roo.log([ sm.getSelectedCell() ? sm.getSelectedCell()[0] : 'NO' , rowIndex ]);
58177 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
58180 if (e.hasModifier()){
58181 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
58184 Roo.log("getDragData");
58189 rowIndex: rowIndex,
58190 selections: sm.getSelections ? sm.getSelections() : (
58191 sm.getSelectedCell() ? [ this.grid.ds.getAt(sm.getSelectedCell()[0]) ] : [])
58198 onInitDrag : function(e){
58199 var data = this.dragData;
58200 this.ddel.innerHTML = this.grid.getDragDropText();
58201 this.proxy.update(this.ddel);
58202 // fire start drag?
58205 afterRepair : function(){
58206 this.dragging = false;
58209 getRepairXY : function(e, data){
58213 onEndDrag : function(data, e){
58217 onValidDrop : function(dd, e, id){
58222 beforeInvalidDrop : function(e, id){
58227 * Ext JS Library 1.1.1
58228 * Copyright(c) 2006-2007, Ext JS, LLC.
58230 * Originally Released Under LGPL - original licence link has changed is not relivant.
58233 * <script type="text/javascript">
58238 * @class Roo.grid.ColumnModel
58239 * @extends Roo.util.Observable
58240 * This is the default implementation of a ColumnModel used by the Grid. It defines
58241 * the columns in the grid.
58244 var colModel = new Roo.grid.ColumnModel([
58245 {header: "Ticker", width: 60, sortable: true, locked: true},
58246 {header: "Company Name", width: 150, sortable: true},
58247 {header: "Market Cap.", width: 100, sortable: true},
58248 {header: "$ Sales", width: 100, sortable: true, renderer: money},
58249 {header: "Employees", width: 100, sortable: true, resizable: false}
58254 * The config options listed for this class are options which may appear in each
58255 * individual column definition.
58256 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
58258 * @param {Object} config An Array of column config objects. See this class's
58259 * config objects for details.
58261 Roo.grid.ColumnModel = function(config){
58263 * The config passed into the constructor
58265 this.config = config;
58268 // if no id, create one
58269 // if the column does not have a dataIndex mapping,
58270 // map it to the order it is in the config
58271 for(var i = 0, len = config.length; i < len; i++){
58273 if(typeof c.dataIndex == "undefined"){
58276 if(typeof c.renderer == "string"){
58277 c.renderer = Roo.util.Format[c.renderer];
58279 if(typeof c.id == "undefined"){
58282 if(c.editor && c.editor.xtype){
58283 c.editor = Roo.factory(c.editor, Roo.grid);
58285 if(c.editor && c.editor.isFormField){
58286 c.editor = new Roo.grid.GridEditor(c.editor);
58288 this.lookup[c.id] = c;
58292 * The width of columns which have no width specified (defaults to 100)
58295 this.defaultWidth = 100;
58298 * Default sortable of columns which have no sortable specified (defaults to false)
58301 this.defaultSortable = false;
58305 * @event widthchange
58306 * Fires when the width of a column changes.
58307 * @param {ColumnModel} this
58308 * @param {Number} columnIndex The column index
58309 * @param {Number} newWidth The new width
58311 "widthchange": true,
58313 * @event headerchange
58314 * Fires when the text of a header changes.
58315 * @param {ColumnModel} this
58316 * @param {Number} columnIndex The column index
58317 * @param {Number} newText The new header text
58319 "headerchange": true,
58321 * @event hiddenchange
58322 * Fires when a column is hidden or "unhidden".
58323 * @param {ColumnModel} this
58324 * @param {Number} columnIndex The column index
58325 * @param {Boolean} hidden true if hidden, false otherwise
58327 "hiddenchange": true,
58329 * @event columnmoved
58330 * Fires when a column is moved.
58331 * @param {ColumnModel} this
58332 * @param {Number} oldIndex
58333 * @param {Number} newIndex
58335 "columnmoved" : true,
58337 * @event columlockchange
58338 * Fires when a column's locked state is changed
58339 * @param {ColumnModel} this
58340 * @param {Number} colIndex
58341 * @param {Boolean} locked true if locked
58343 "columnlockchange" : true
58345 Roo.grid.ColumnModel.superclass.constructor.call(this);
58347 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
58349 * @cfg {String} header The header text to display in the Grid view.
58352 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
58353 * {@link Roo.data.Record} definition from which to draw the column's value. If not
58354 * specified, the column's index is used as an index into the Record's data Array.
58357 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
58358 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
58361 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
58362 * Defaults to the value of the {@link #defaultSortable} property.
58363 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
58366 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
58369 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
58372 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
58375 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
58378 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
58379 * given the cell's data value. See {@link #setRenderer}. If not specified, the
58380 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
58381 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
58384 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
58387 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
58390 * @cfg {String} valign (Optional) Set the CSS vertical-align property of the column (eg. middle, top, bottom etc). Defaults to undefined.
58393 * @cfg {String} cursor (Optional)
58396 * @cfg {String} tooltip (Optional)
58399 * @cfg {Number} xs (Optional)
58402 * @cfg {Number} sm (Optional)
58405 * @cfg {Number} md (Optional)
58408 * @cfg {Number} lg (Optional)
58411 * Returns the id of the column at the specified index.
58412 * @param {Number} index The column index
58413 * @return {String} the id
58415 getColumnId : function(index){
58416 return this.config[index].id;
58420 * Returns the column for a specified id.
58421 * @param {String} id The column id
58422 * @return {Object} the column
58424 getColumnById : function(id){
58425 return this.lookup[id];
58430 * Returns the column for a specified dataIndex.
58431 * @param {String} dataIndex The column dataIndex
58432 * @return {Object|Boolean} the column or false if not found
58434 getColumnByDataIndex: function(dataIndex){
58435 var index = this.findColumnIndex(dataIndex);
58436 return index > -1 ? this.config[index] : false;
58440 * Returns the index for a specified column id.
58441 * @param {String} id The column id
58442 * @return {Number} the index, or -1 if not found
58444 getIndexById : function(id){
58445 for(var i = 0, len = this.config.length; i < len; i++){
58446 if(this.config[i].id == id){
58454 * Returns the index for a specified column dataIndex.
58455 * @param {String} dataIndex The column dataIndex
58456 * @return {Number} the index, or -1 if not found
58459 findColumnIndex : function(dataIndex){
58460 for(var i = 0, len = this.config.length; i < len; i++){
58461 if(this.config[i].dataIndex == dataIndex){
58469 moveColumn : function(oldIndex, newIndex){
58470 var c = this.config[oldIndex];
58471 this.config.splice(oldIndex, 1);
58472 this.config.splice(newIndex, 0, c);
58473 this.dataMap = null;
58474 this.fireEvent("columnmoved", this, oldIndex, newIndex);
58477 isLocked : function(colIndex){
58478 return this.config[colIndex].locked === true;
58481 setLocked : function(colIndex, value, suppressEvent){
58482 if(this.isLocked(colIndex) == value){
58485 this.config[colIndex].locked = value;
58486 if(!suppressEvent){
58487 this.fireEvent("columnlockchange", this, colIndex, value);
58491 getTotalLockedWidth : function(){
58492 var totalWidth = 0;
58493 for(var i = 0; i < this.config.length; i++){
58494 if(this.isLocked(i) && !this.isHidden(i)){
58495 this.totalWidth += this.getColumnWidth(i);
58501 getLockedCount : function(){
58502 for(var i = 0, len = this.config.length; i < len; i++){
58503 if(!this.isLocked(i)){
58508 return this.config.length;
58512 * Returns the number of columns.
58515 getColumnCount : function(visibleOnly){
58516 if(visibleOnly === true){
58518 for(var i = 0, len = this.config.length; i < len; i++){
58519 if(!this.isHidden(i)){
58525 return this.config.length;
58529 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
58530 * @param {Function} fn
58531 * @param {Object} scope (optional)
58532 * @return {Array} result
58534 getColumnsBy : function(fn, scope){
58536 for(var i = 0, len = this.config.length; i < len; i++){
58537 var c = this.config[i];
58538 if(fn.call(scope||this, c, i) === true){
58546 * Returns true if the specified column is sortable.
58547 * @param {Number} col The column index
58548 * @return {Boolean}
58550 isSortable : function(col){
58551 if(typeof this.config[col].sortable == "undefined"){
58552 return this.defaultSortable;
58554 return this.config[col].sortable;
58558 * Returns the rendering (formatting) function defined for the column.
58559 * @param {Number} col The column index.
58560 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
58562 getRenderer : function(col){
58563 if(!this.config[col].renderer){
58564 return Roo.grid.ColumnModel.defaultRenderer;
58566 return this.config[col].renderer;
58570 * Sets the rendering (formatting) function for a column.
58571 * @param {Number} col The column index
58572 * @param {Function} fn The function to use to process the cell's raw data
58573 * to return HTML markup for the grid view. The render function is called with
58574 * the following parameters:<ul>
58575 * <li>Data value.</li>
58576 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
58577 * <li>css A CSS style string to apply to the table cell.</li>
58578 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
58579 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
58580 * <li>Row index</li>
58581 * <li>Column index</li>
58582 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
58584 setRenderer : function(col, fn){
58585 this.config[col].renderer = fn;
58589 * Returns the width for the specified column.
58590 * @param {Number} col The column index
58593 getColumnWidth : function(col){
58594 return this.config[col].width * 1 || this.defaultWidth;
58598 * Sets the width for a column.
58599 * @param {Number} col The column index
58600 * @param {Number} width The new width
58602 setColumnWidth : function(col, width, suppressEvent){
58603 this.config[col].width = width;
58604 this.totalWidth = null;
58605 if(!suppressEvent){
58606 this.fireEvent("widthchange", this, col, width);
58611 * Returns the total width of all columns.
58612 * @param {Boolean} includeHidden True to include hidden column widths
58615 getTotalWidth : function(includeHidden){
58616 if(!this.totalWidth){
58617 this.totalWidth = 0;
58618 for(var i = 0, len = this.config.length; i < len; i++){
58619 if(includeHidden || !this.isHidden(i)){
58620 this.totalWidth += this.getColumnWidth(i);
58624 return this.totalWidth;
58628 * Returns the header for the specified column.
58629 * @param {Number} col The column index
58632 getColumnHeader : function(col){
58633 return this.config[col].header;
58637 * Sets the header for a column.
58638 * @param {Number} col The column index
58639 * @param {String} header The new header
58641 setColumnHeader : function(col, header){
58642 this.config[col].header = header;
58643 this.fireEvent("headerchange", this, col, header);
58647 * Returns the tooltip for the specified column.
58648 * @param {Number} col The column index
58651 getColumnTooltip : function(col){
58652 return this.config[col].tooltip;
58655 * Sets the tooltip for a column.
58656 * @param {Number} col The column index
58657 * @param {String} tooltip The new tooltip
58659 setColumnTooltip : function(col, tooltip){
58660 this.config[col].tooltip = tooltip;
58664 * Returns the dataIndex for the specified column.
58665 * @param {Number} col The column index
58668 getDataIndex : function(col){
58669 return this.config[col].dataIndex;
58673 * Sets the dataIndex for a column.
58674 * @param {Number} col The column index
58675 * @param {Number} dataIndex The new dataIndex
58677 setDataIndex : function(col, dataIndex){
58678 this.config[col].dataIndex = dataIndex;
58684 * Returns true if the cell is editable.
58685 * @param {Number} colIndex The column index
58686 * @param {Number} rowIndex The row index - this is nto actually used..?
58687 * @return {Boolean}
58689 isCellEditable : function(colIndex, rowIndex){
58690 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
58694 * Returns the editor defined for the cell/column.
58695 * return false or null to disable editing.
58696 * @param {Number} colIndex The column index
58697 * @param {Number} rowIndex The row index
58700 getCellEditor : function(colIndex, rowIndex){
58701 return this.config[colIndex].editor;
58705 * Sets if a column is editable.
58706 * @param {Number} col The column index
58707 * @param {Boolean} editable True if the column is editable
58709 setEditable : function(col, editable){
58710 this.config[col].editable = editable;
58715 * Returns true if the column is hidden.
58716 * @param {Number} colIndex The column index
58717 * @return {Boolean}
58719 isHidden : function(colIndex){
58720 return this.config[colIndex].hidden;
58725 * Returns true if the column width cannot be changed
58727 isFixed : function(colIndex){
58728 return this.config[colIndex].fixed;
58732 * Returns true if the column can be resized
58733 * @return {Boolean}
58735 isResizable : function(colIndex){
58736 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
58739 * Sets if a column is hidden.
58740 * @param {Number} colIndex The column index
58741 * @param {Boolean} hidden True if the column is hidden
58743 setHidden : function(colIndex, hidden){
58744 this.config[colIndex].hidden = hidden;
58745 this.totalWidth = null;
58746 this.fireEvent("hiddenchange", this, colIndex, hidden);
58750 * Sets the editor for a column.
58751 * @param {Number} col The column index
58752 * @param {Object} editor The editor object
58754 setEditor : function(col, editor){
58755 this.config[col].editor = editor;
58759 Roo.grid.ColumnModel.defaultRenderer = function(value)
58761 if(typeof value == "object") {
58764 if(typeof value == "string" && value.length < 1){
58768 return String.format("{0}", value);
58771 // Alias for backwards compatibility
58772 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
58775 * Ext JS Library 1.1.1
58776 * Copyright(c) 2006-2007, Ext JS, LLC.
58778 * Originally Released Under LGPL - original licence link has changed is not relivant.
58781 * <script type="text/javascript">
58785 * @class Roo.grid.AbstractSelectionModel
58786 * @extends Roo.util.Observable
58787 * Abstract base class for grid SelectionModels. It provides the interface that should be
58788 * implemented by descendant classes. This class should not be directly instantiated.
58791 Roo.grid.AbstractSelectionModel = function(){
58792 this.locked = false;
58793 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
58796 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
58797 /** @ignore Called by the grid automatically. Do not call directly. */
58798 init : function(grid){
58804 * Locks the selections.
58807 this.locked = true;
58811 * Unlocks the selections.
58813 unlock : function(){
58814 this.locked = false;
58818 * Returns true if the selections are locked.
58819 * @return {Boolean}
58821 isLocked : function(){
58822 return this.locked;
58826 * Ext JS Library 1.1.1
58827 * Copyright(c) 2006-2007, Ext JS, LLC.
58829 * Originally Released Under LGPL - original licence link has changed is not relivant.
58832 * <script type="text/javascript">
58835 * @extends Roo.grid.AbstractSelectionModel
58836 * @class Roo.grid.RowSelectionModel
58837 * The default SelectionModel used by {@link Roo.grid.Grid}.
58838 * It supports multiple selections and keyboard selection/navigation.
58840 * @param {Object} config
58842 Roo.grid.RowSelectionModel = function(config){
58843 Roo.apply(this, config);
58844 this.selections = new Roo.util.MixedCollection(false, function(o){
58849 this.lastActive = false;
58853 * @event selectionchange
58854 * Fires when the selection changes
58855 * @param {SelectionModel} this
58857 "selectionchange" : true,
58859 * @event afterselectionchange
58860 * Fires after the selection changes (eg. by key press or clicking)
58861 * @param {SelectionModel} this
58863 "afterselectionchange" : true,
58865 * @event beforerowselect
58866 * Fires when a row is selected being selected, return false to cancel.
58867 * @param {SelectionModel} this
58868 * @param {Number} rowIndex The selected index
58869 * @param {Boolean} keepExisting False if other selections will be cleared
58871 "beforerowselect" : true,
58874 * Fires when a row is selected.
58875 * @param {SelectionModel} this
58876 * @param {Number} rowIndex The selected index
58877 * @param {Roo.data.Record} r The record
58879 "rowselect" : true,
58881 * @event rowdeselect
58882 * Fires when a row is deselected.
58883 * @param {SelectionModel} this
58884 * @param {Number} rowIndex The selected index
58886 "rowdeselect" : true
58888 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
58889 this.locked = false;
58892 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
58894 * @cfg {Boolean} singleSelect
58895 * True to allow selection of only one row at a time (defaults to false)
58897 singleSelect : false,
58900 initEvents : function(){
58902 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
58903 this.grid.on("mousedown", this.handleMouseDown, this);
58904 }else{ // allow click to work like normal
58905 this.grid.on("rowclick", this.handleDragableRowClick, this);
58908 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
58909 "up" : function(e){
58911 this.selectPrevious(e.shiftKey);
58912 }else if(this.last !== false && this.lastActive !== false){
58913 var last = this.last;
58914 this.selectRange(this.last, this.lastActive-1);
58915 this.grid.getView().focusRow(this.lastActive);
58916 if(last !== false){
58920 this.selectFirstRow();
58922 this.fireEvent("afterselectionchange", this);
58924 "down" : function(e){
58926 this.selectNext(e.shiftKey);
58927 }else if(this.last !== false && this.lastActive !== false){
58928 var last = this.last;
58929 this.selectRange(this.last, this.lastActive+1);
58930 this.grid.getView().focusRow(this.lastActive);
58931 if(last !== false){
58935 this.selectFirstRow();
58937 this.fireEvent("afterselectionchange", this);
58942 var view = this.grid.view;
58943 view.on("refresh", this.onRefresh, this);
58944 view.on("rowupdated", this.onRowUpdated, this);
58945 view.on("rowremoved", this.onRemove, this);
58949 onRefresh : function(){
58950 var ds = this.grid.dataSource, i, v = this.grid.view;
58951 var s = this.selections;
58952 s.each(function(r){
58953 if((i = ds.indexOfId(r.id)) != -1){
58955 s.add(ds.getAt(i)); // updating the selection relate data
58963 onRemove : function(v, index, r){
58964 this.selections.remove(r);
58968 onRowUpdated : function(v, index, r){
58969 if(this.isSelected(r)){
58970 v.onRowSelect(index);
58976 * @param {Array} records The records to select
58977 * @param {Boolean} keepExisting (optional) True to keep existing selections
58979 selectRecords : function(records, keepExisting){
58981 this.clearSelections();
58983 var ds = this.grid.dataSource;
58984 for(var i = 0, len = records.length; i < len; i++){
58985 this.selectRow(ds.indexOf(records[i]), true);
58990 * Gets the number of selected rows.
58993 getCount : function(){
58994 return this.selections.length;
58998 * Selects the first row in the grid.
59000 selectFirstRow : function(){
59005 * Select the last row.
59006 * @param {Boolean} keepExisting (optional) True to keep existing selections
59008 selectLastRow : function(keepExisting){
59009 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
59013 * Selects the row immediately following the last selected row.
59014 * @param {Boolean} keepExisting (optional) True to keep existing selections
59016 selectNext : function(keepExisting){
59017 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
59018 this.selectRow(this.last+1, keepExisting);
59019 this.grid.getView().focusRow(this.last);
59024 * Selects the row that precedes the last selected row.
59025 * @param {Boolean} keepExisting (optional) True to keep existing selections
59027 selectPrevious : function(keepExisting){
59029 this.selectRow(this.last-1, keepExisting);
59030 this.grid.getView().focusRow(this.last);
59035 * Returns the selected records
59036 * @return {Array} Array of selected records
59038 getSelections : function(){
59039 return [].concat(this.selections.items);
59043 * Returns the first selected record.
59046 getSelected : function(){
59047 return this.selections.itemAt(0);
59052 * Clears all selections.
59054 clearSelections : function(fast){
59059 var ds = this.grid.dataSource;
59060 var s = this.selections;
59061 s.each(function(r){
59062 this.deselectRow(ds.indexOfId(r.id));
59066 this.selections.clear();
59073 * Selects all rows.
59075 selectAll : function(){
59079 this.selections.clear();
59080 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
59081 this.selectRow(i, true);
59086 * Returns True if there is a selection.
59087 * @return {Boolean}
59089 hasSelection : function(){
59090 return this.selections.length > 0;
59094 * Returns True if the specified row is selected.
59095 * @param {Number/Record} record The record or index of the record to check
59096 * @return {Boolean}
59098 isSelected : function(index){
59099 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
59100 return (r && this.selections.key(r.id) ? true : false);
59104 * Returns True if the specified record id is selected.
59105 * @param {String} id The id of record to check
59106 * @return {Boolean}
59108 isIdSelected : function(id){
59109 return (this.selections.key(id) ? true : false);
59113 handleMouseDown : function(e, t){
59114 var view = this.grid.getView(), rowIndex;
59115 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
59118 if(e.shiftKey && this.last !== false){
59119 var last = this.last;
59120 this.selectRange(last, rowIndex, e.ctrlKey);
59121 this.last = last; // reset the last
59122 view.focusRow(rowIndex);
59124 var isSelected = this.isSelected(rowIndex);
59125 if(e.button !== 0 && isSelected){
59126 view.focusRow(rowIndex);
59127 }else if(e.ctrlKey && isSelected){
59128 this.deselectRow(rowIndex);
59129 }else if(!isSelected){
59130 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
59131 view.focusRow(rowIndex);
59134 this.fireEvent("afterselectionchange", this);
59137 handleDragableRowClick : function(grid, rowIndex, e)
59139 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
59140 this.selectRow(rowIndex, false);
59141 grid.view.focusRow(rowIndex);
59142 this.fireEvent("afterselectionchange", this);
59147 * Selects multiple rows.
59148 * @param {Array} rows Array of the indexes of the row to select
59149 * @param {Boolean} keepExisting (optional) True to keep existing selections
59151 selectRows : function(rows, keepExisting){
59153 this.clearSelections();
59155 for(var i = 0, len = rows.length; i < len; i++){
59156 this.selectRow(rows[i], true);
59161 * Selects a range of rows. All rows in between startRow and endRow are also selected.
59162 * @param {Number} startRow The index of the first row in the range
59163 * @param {Number} endRow The index of the last row in the range
59164 * @param {Boolean} keepExisting (optional) True to retain existing selections
59166 selectRange : function(startRow, endRow, keepExisting){
59171 this.clearSelections();
59173 if(startRow <= endRow){
59174 for(var i = startRow; i <= endRow; i++){
59175 this.selectRow(i, true);
59178 for(var i = startRow; i >= endRow; i--){
59179 this.selectRow(i, true);
59185 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
59186 * @param {Number} startRow The index of the first row in the range
59187 * @param {Number} endRow The index of the last row in the range
59189 deselectRange : function(startRow, endRow, preventViewNotify){
59193 for(var i = startRow; i <= endRow; i++){
59194 this.deselectRow(i, preventViewNotify);
59200 * @param {Number} row The index of the row to select
59201 * @param {Boolean} keepExisting (optional) True to keep existing selections
59203 selectRow : function(index, keepExisting, preventViewNotify){
59204 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) {
59207 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
59208 if(!keepExisting || this.singleSelect){
59209 this.clearSelections();
59211 var r = this.grid.dataSource.getAt(index);
59212 this.selections.add(r);
59213 this.last = this.lastActive = index;
59214 if(!preventViewNotify){
59215 this.grid.getView().onRowSelect(index);
59217 this.fireEvent("rowselect", this, index, r);
59218 this.fireEvent("selectionchange", this);
59224 * @param {Number} row The index of the row to deselect
59226 deselectRow : function(index, preventViewNotify){
59230 if(this.last == index){
59233 if(this.lastActive == index){
59234 this.lastActive = false;
59236 var r = this.grid.dataSource.getAt(index);
59237 this.selections.remove(r);
59238 if(!preventViewNotify){
59239 this.grid.getView().onRowDeselect(index);
59241 this.fireEvent("rowdeselect", this, index);
59242 this.fireEvent("selectionchange", this);
59246 restoreLast : function(){
59248 this.last = this._last;
59253 acceptsNav : function(row, col, cm){
59254 return !cm.isHidden(col) && cm.isCellEditable(col, row);
59258 onEditorKey : function(field, e){
59259 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
59264 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
59266 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
59268 }else if(k == e.ENTER && !e.ctrlKey){
59272 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
59274 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
59276 }else if(k == e.ESC){
59280 g.startEditing(newCell[0], newCell[1]);
59285 * Ext JS Library 1.1.1
59286 * Copyright(c) 2006-2007, Ext JS, LLC.
59288 * Originally Released Under LGPL - original licence link has changed is not relivant.
59291 * <script type="text/javascript">
59294 * @class Roo.grid.CellSelectionModel
59295 * @extends Roo.grid.AbstractSelectionModel
59296 * This class provides the basic implementation for cell selection in a grid.
59298 * @param {Object} config The object containing the configuration of this model.
59299 * @cfg {Boolean} enter_is_tab Enter behaves the same as tab. (eg. goes to next cell) default: false
59301 Roo.grid.CellSelectionModel = function(config){
59302 Roo.apply(this, config);
59304 this.selection = null;
59308 * @event beforerowselect
59309 * Fires before a cell is selected.
59310 * @param {SelectionModel} this
59311 * @param {Number} rowIndex The selected row index
59312 * @param {Number} colIndex The selected cell index
59314 "beforecellselect" : true,
59316 * @event cellselect
59317 * Fires when a cell is selected.
59318 * @param {SelectionModel} this
59319 * @param {Number} rowIndex The selected row index
59320 * @param {Number} colIndex The selected cell index
59322 "cellselect" : true,
59324 * @event selectionchange
59325 * Fires when the active selection changes.
59326 * @param {SelectionModel} this
59327 * @param {Object} selection null for no selection or an object (o) with two properties
59329 <li>o.record: the record object for the row the selection is in</li>
59330 <li>o.cell: An array of [rowIndex, columnIndex]</li>
59333 "selectionchange" : true,
59336 * Fires when the tab (or enter) was pressed on the last editable cell
59337 * You can use this to trigger add new row.
59338 * @param {SelectionModel} this
59342 * @event beforeeditnext
59343 * Fires before the next editable sell is made active
59344 * You can use this to skip to another cell or fire the tabend
59345 * if you set cell to false
59346 * @param {Object} eventdata object : { cell : [ row, col ] }
59348 "beforeeditnext" : true
59350 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
59353 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
59355 enter_is_tab: false,
59358 initEvents : function(){
59359 this.grid.on("mousedown", this.handleMouseDown, this);
59360 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
59361 var view = this.grid.view;
59362 view.on("refresh", this.onViewChange, this);
59363 view.on("rowupdated", this.onRowUpdated, this);
59364 view.on("beforerowremoved", this.clearSelections, this);
59365 view.on("beforerowsinserted", this.clearSelections, this);
59366 if(this.grid.isEditor){
59367 this.grid.on("beforeedit", this.beforeEdit, this);
59372 beforeEdit : function(e){
59373 this.select(e.row, e.column, false, true, e.record);
59377 onRowUpdated : function(v, index, r){
59378 if(this.selection && this.selection.record == r){
59379 v.onCellSelect(index, this.selection.cell[1]);
59384 onViewChange : function(){
59385 this.clearSelections(true);
59389 * Returns the currently selected cell,.
59390 * @return {Array} The selected cell (row, column) or null if none selected.
59392 getSelectedCell : function(){
59393 return this.selection ? this.selection.cell : null;
59397 * Clears all selections.
59398 * @param {Boolean} true to prevent the gridview from being notified about the change.
59400 clearSelections : function(preventNotify){
59401 var s = this.selection;
59403 if(preventNotify !== true){
59404 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
59406 this.selection = null;
59407 this.fireEvent("selectionchange", this, null);
59412 * Returns true if there is a selection.
59413 * @return {Boolean}
59415 hasSelection : function(){
59416 return this.selection ? true : false;
59420 handleMouseDown : function(e, t){
59421 var v = this.grid.getView();
59422 if(this.isLocked()){
59425 var row = v.findRowIndex(t);
59426 var cell = v.findCellIndex(t);
59427 if(row !== false && cell !== false){
59428 this.select(row, cell);
59434 * @param {Number} rowIndex
59435 * @param {Number} collIndex
59437 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
59438 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
59439 this.clearSelections();
59440 r = r || this.grid.dataSource.getAt(rowIndex);
59443 cell : [rowIndex, colIndex]
59445 if(!preventViewNotify){
59446 var v = this.grid.getView();
59447 v.onCellSelect(rowIndex, colIndex);
59448 if(preventFocus !== true){
59449 v.focusCell(rowIndex, colIndex);
59452 this.fireEvent("cellselect", this, rowIndex, colIndex);
59453 this.fireEvent("selectionchange", this, this.selection);
59458 isSelectable : function(rowIndex, colIndex, cm){
59459 return !cm.isHidden(colIndex);
59463 handleKeyDown : function(e){
59464 //Roo.log('Cell Sel Model handleKeyDown');
59465 if(!e.isNavKeyPress()){
59468 var g = this.grid, s = this.selection;
59471 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
59473 this.select(cell[0], cell[1]);
59478 var walk = function(row, col, step){
59479 return g.walkCells(row, col, step, sm.isSelectable, sm);
59481 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
59488 // handled by onEditorKey
59489 if (g.isEditor && g.editing) {
59493 newCell = walk(r, c-1, -1);
59495 newCell = walk(r, c+1, 1);
59500 newCell = walk(r+1, c, 1);
59504 newCell = walk(r-1, c, -1);
59508 newCell = walk(r, c+1, 1);
59512 newCell = walk(r, c-1, -1);
59517 if(g.isEditor && !g.editing){
59518 g.startEditing(r, c);
59527 this.select(newCell[0], newCell[1]);
59533 acceptsNav : function(row, col, cm){
59534 return !cm.isHidden(col) && cm.isCellEditable(col, row);
59538 * @param {Number} field (not used) - as it's normally used as a listener
59539 * @param {Number} e - event - fake it by using
59541 * var e = Roo.EventObjectImpl.prototype;
59542 * e.keyCode = e.TAB
59546 onEditorKey : function(field, e){
59548 var k = e.getKey(),
59551 ed = g.activeEditor,
59553 ///Roo.log('onEditorKey' + k);
59556 if (this.enter_is_tab && k == e.ENTER) {
59562 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
59564 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
59570 } else if(k == e.ENTER && !e.ctrlKey){
59573 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
59575 } else if(k == e.ESC){
59580 var ecall = { cell : newCell, forward : forward };
59581 this.fireEvent('beforeeditnext', ecall );
59582 newCell = ecall.cell;
59583 forward = ecall.forward;
59587 //Roo.log('next cell after edit');
59588 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
59589 } else if (forward) {
59590 // tabbed past last
59591 this.fireEvent.defer(100, this, ['tabend',this]);
59596 * Ext JS Library 1.1.1
59597 * Copyright(c) 2006-2007, Ext JS, LLC.
59599 * Originally Released Under LGPL - original licence link has changed is not relivant.
59602 * <script type="text/javascript">
59606 * @class Roo.grid.EditorGrid
59607 * @extends Roo.grid.Grid
59608 * Class for creating and editable grid.
59609 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
59610 * The container MUST have some type of size defined for the grid to fill. The container will be
59611 * automatically set to position relative if it isn't already.
59612 * @param {Object} dataSource The data model to bind to
59613 * @param {Object} colModel The column model with info about this grid's columns
59615 Roo.grid.EditorGrid = function(container, config){
59616 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
59617 this.getGridEl().addClass("xedit-grid");
59619 if(!this.selModel){
59620 this.selModel = new Roo.grid.CellSelectionModel();
59623 this.activeEditor = null;
59627 * @event beforeedit
59628 * Fires before cell editing is triggered. The edit event object has the following properties <br />
59629 * <ul style="padding:5px;padding-left:16px;">
59630 * <li>grid - This grid</li>
59631 * <li>record - The record being edited</li>
59632 * <li>field - The field name being edited</li>
59633 * <li>value - The value for the field being edited.</li>
59634 * <li>row - The grid row index</li>
59635 * <li>column - The grid column index</li>
59636 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
59638 * @param {Object} e An edit event (see above for description)
59640 "beforeedit" : true,
59643 * Fires after a cell is edited. <br />
59644 * <ul style="padding:5px;padding-left:16px;">
59645 * <li>grid - This grid</li>
59646 * <li>record - The record being edited</li>
59647 * <li>field - The field name being edited</li>
59648 * <li>value - The value being set</li>
59649 * <li>originalValue - The original value for the field, before the edit.</li>
59650 * <li>row - The grid row index</li>
59651 * <li>column - The grid column index</li>
59653 * @param {Object} e An edit event (see above for description)
59655 "afteredit" : true,
59657 * @event validateedit
59658 * Fires after a cell is edited, but before the value is set in the record.
59659 * You can use this to modify the value being set in the field, Return false
59660 * to cancel the change. The edit event object has the following properties <br />
59661 * <ul style="padding:5px;padding-left:16px;">
59662 * <li>editor - This editor</li>
59663 * <li>grid - This grid</li>
59664 * <li>record - The record being edited</li>
59665 * <li>field - The field name being edited</li>
59666 * <li>value - The value being set</li>
59667 * <li>originalValue - The original value for the field, before the edit.</li>
59668 * <li>row - The grid row index</li>
59669 * <li>column - The grid column index</li>
59670 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
59672 * @param {Object} e An edit event (see above for description)
59674 "validateedit" : true
59676 this.on("bodyscroll", this.stopEditing, this);
59677 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
59680 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
59682 * @cfg {Number} clicksToEdit
59683 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
59690 trackMouseOver: false, // causes very odd FF errors
59692 onCellDblClick : function(g, row, col){
59693 this.startEditing(row, col);
59696 onEditComplete : function(ed, value, startValue){
59697 this.editing = false;
59698 this.activeEditor = null;
59699 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
59701 var field = this.colModel.getDataIndex(ed.col);
59706 originalValue: startValue,
59713 var cell = Roo.get(this.view.getCell(ed.row,ed.col));
59716 if(String(value) !== String(startValue)){
59718 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
59719 r.set(field, e.value);
59720 // if we are dealing with a combo box..
59721 // then we also set the 'name' colum to be the displayField
59722 if (ed.field.displayField && ed.field.name) {
59723 r.set(ed.field.name, ed.field.el.dom.value);
59726 delete e.cancel; //?? why!!!
59727 this.fireEvent("afteredit", e);
59730 this.fireEvent("afteredit", e); // always fire it!
59732 this.view.focusCell(ed.row, ed.col);
59736 * Starts editing the specified for the specified row/column
59737 * @param {Number} rowIndex
59738 * @param {Number} colIndex
59740 startEditing : function(row, col){
59741 this.stopEditing();
59742 if(this.colModel.isCellEditable(col, row)){
59743 this.view.ensureVisible(row, col, true);
59745 var r = this.dataSource.getAt(row);
59746 var field = this.colModel.getDataIndex(col);
59747 var cell = Roo.get(this.view.getCell(row,col));
59752 value: r.data[field],
59757 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
59758 this.editing = true;
59759 var ed = this.colModel.getCellEditor(col, row);
59765 ed.render(ed.parentEl || document.body);
59771 (function(){ // complex but required for focus issues in safari, ie and opera
59775 ed.on("complete", this.onEditComplete, this, {single: true});
59776 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
59777 this.activeEditor = ed;
59778 var v = r.data[field];
59779 ed.startEdit(this.view.getCell(row, col), v);
59780 // combo's with 'displayField and name set
59781 if (ed.field.displayField && ed.field.name) {
59782 ed.field.el.dom.value = r.data[ed.field.name];
59786 }).defer(50, this);
59792 * Stops any active editing
59794 stopEditing : function(){
59795 if(this.activeEditor){
59796 this.activeEditor.completeEdit();
59798 this.activeEditor = null;
59802 * Called to get grid's drag proxy text, by default returns this.ddText.
59805 getDragDropText : function(){
59806 var count = this.selModel.getSelectedCell() ? 1 : 0;
59807 return String.format(this.ddText, count, count == 1 ? '' : 's');
59812 * Ext JS Library 1.1.1
59813 * Copyright(c) 2006-2007, Ext JS, LLC.
59815 * Originally Released Under LGPL - original licence link has changed is not relivant.
59818 * <script type="text/javascript">
59821 // private - not really -- you end up using it !
59822 // This is a support class used internally by the Grid components
59825 * @class Roo.grid.GridEditor
59826 * @extends Roo.Editor
59827 * Class for creating and editable grid elements.
59828 * @param {Object} config any settings (must include field)
59830 Roo.grid.GridEditor = function(field, config){
59831 if (!config && field.field) {
59833 field = Roo.factory(config.field, Roo.form);
59835 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
59836 field.monitorTab = false;
59839 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
59842 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
59845 alignment: "tl-tl",
59848 cls: "x-small-editor x-grid-editor",
59853 * Ext JS Library 1.1.1
59854 * Copyright(c) 2006-2007, Ext JS, LLC.
59856 * Originally Released Under LGPL - original licence link has changed is not relivant.
59859 * <script type="text/javascript">
59864 Roo.grid.PropertyRecord = Roo.data.Record.create([
59865 {name:'name',type:'string'}, 'value'
59869 Roo.grid.PropertyStore = function(grid, source){
59871 this.store = new Roo.data.Store({
59872 recordType : Roo.grid.PropertyRecord
59874 this.store.on('update', this.onUpdate, this);
59876 this.setSource(source);
59878 Roo.grid.PropertyStore.superclass.constructor.call(this);
59883 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
59884 setSource : function(o){
59886 this.store.removeAll();
59889 if(this.isEditableValue(o[k])){
59890 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
59893 this.store.loadRecords({records: data}, {}, true);
59896 onUpdate : function(ds, record, type){
59897 if(type == Roo.data.Record.EDIT){
59898 var v = record.data['value'];
59899 var oldValue = record.modified['value'];
59900 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
59901 this.source[record.id] = v;
59903 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
59910 getProperty : function(row){
59911 return this.store.getAt(row);
59914 isEditableValue: function(val){
59915 if(val && val instanceof Date){
59917 }else if(typeof val == 'object' || typeof val == 'function'){
59923 setValue : function(prop, value){
59924 this.source[prop] = value;
59925 this.store.getById(prop).set('value', value);
59928 getSource : function(){
59929 return this.source;
59933 Roo.grid.PropertyColumnModel = function(grid, store){
59936 g.PropertyColumnModel.superclass.constructor.call(this, [
59937 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
59938 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
59940 this.store = store;
59941 this.bselect = Roo.DomHelper.append(document.body, {
59942 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
59943 {tag: 'option', value: 'true', html: 'true'},
59944 {tag: 'option', value: 'false', html: 'false'}
59947 Roo.id(this.bselect);
59950 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
59951 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
59952 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
59953 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
59954 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
59956 this.renderCellDelegate = this.renderCell.createDelegate(this);
59957 this.renderPropDelegate = this.renderProp.createDelegate(this);
59960 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
59964 valueText : 'Value',
59966 dateFormat : 'm/j/Y',
59969 renderDate : function(dateVal){
59970 return dateVal.dateFormat(this.dateFormat);
59973 renderBool : function(bVal){
59974 return bVal ? 'true' : 'false';
59977 isCellEditable : function(colIndex, rowIndex){
59978 return colIndex == 1;
59981 getRenderer : function(col){
59983 this.renderCellDelegate : this.renderPropDelegate;
59986 renderProp : function(v){
59987 return this.getPropertyName(v);
59990 renderCell : function(val){
59992 if(val instanceof Date){
59993 rv = this.renderDate(val);
59994 }else if(typeof val == 'boolean'){
59995 rv = this.renderBool(val);
59997 return Roo.util.Format.htmlEncode(rv);
60000 getPropertyName : function(name){
60001 var pn = this.grid.propertyNames;
60002 return pn && pn[name] ? pn[name] : name;
60005 getCellEditor : function(colIndex, rowIndex){
60006 var p = this.store.getProperty(rowIndex);
60007 var n = p.data['name'], val = p.data['value'];
60009 if(typeof(this.grid.customEditors[n]) == 'string'){
60010 return this.editors[this.grid.customEditors[n]];
60012 if(typeof(this.grid.customEditors[n]) != 'undefined'){
60013 return this.grid.customEditors[n];
60015 if(val instanceof Date){
60016 return this.editors['date'];
60017 }else if(typeof val == 'number'){
60018 return this.editors['number'];
60019 }else if(typeof val == 'boolean'){
60020 return this.editors['boolean'];
60022 return this.editors['string'];
60028 * @class Roo.grid.PropertyGrid
60029 * @extends Roo.grid.EditorGrid
60030 * This class represents the interface of a component based property grid control.
60031 * <br><br>Usage:<pre><code>
60032 var grid = new Roo.grid.PropertyGrid("my-container-id", {
60040 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
60041 * The container MUST have some type of size defined for the grid to fill. The container will be
60042 * automatically set to position relative if it isn't already.
60043 * @param {Object} config A config object that sets properties on this grid.
60045 Roo.grid.PropertyGrid = function(container, config){
60046 config = config || {};
60047 var store = new Roo.grid.PropertyStore(this);
60048 this.store = store;
60049 var cm = new Roo.grid.PropertyColumnModel(this, store);
60050 store.store.sort('name', 'ASC');
60051 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
60054 enableColLock:false,
60055 enableColumnMove:false,
60057 trackMouseOver: false,
60060 this.getGridEl().addClass('x-props-grid');
60061 this.lastEditRow = null;
60062 this.on('columnresize', this.onColumnResize, this);
60065 * @event beforepropertychange
60066 * Fires before a property changes (return false to stop?)
60067 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
60068 * @param {String} id Record Id
60069 * @param {String} newval New Value
60070 * @param {String} oldval Old Value
60072 "beforepropertychange": true,
60074 * @event propertychange
60075 * Fires after a property changes
60076 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
60077 * @param {String} id Record Id
60078 * @param {String} newval New Value
60079 * @param {String} oldval Old Value
60081 "propertychange": true
60083 this.customEditors = this.customEditors || {};
60085 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
60088 * @cfg {Object} customEditors map of colnames=> custom editors.
60089 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
60090 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
60091 * false disables editing of the field.
60095 * @cfg {Object} propertyNames map of property Names to their displayed value
60098 render : function(){
60099 Roo.grid.PropertyGrid.superclass.render.call(this);
60100 this.autoSize.defer(100, this);
60103 autoSize : function(){
60104 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
60106 this.view.fitColumns();
60110 onColumnResize : function(){
60111 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
60115 * Sets the data for the Grid
60116 * accepts a Key => Value object of all the elements avaiable.
60117 * @param {Object} data to appear in grid.
60119 setSource : function(source){
60120 this.store.setSource(source);
60124 * Gets all the data from the grid.
60125 * @return {Object} data data stored in grid
60127 getSource : function(){
60128 return this.store.getSource();
60137 * @class Roo.grid.Calendar
60138 * @extends Roo.util.Grid
60139 * This class extends the Grid to provide a calendar widget
60140 * <br><br>Usage:<pre><code>
60141 var grid = new Roo.grid.Calendar("my-container-id", {
60144 selModel: mySelectionModel,
60145 autoSizeColumns: true,
60146 monitorWindowResize: false,
60147 trackMouseOver: true
60148 eventstore : real data store..
60154 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
60155 * The container MUST have some type of size defined for the grid to fill. The container will be
60156 * automatically set to position relative if it isn't already.
60157 * @param {Object} config A config object that sets properties on this grid.
60159 Roo.grid.Calendar = function(container, config){
60160 // initialize the container
60161 this.container = Roo.get(container);
60162 this.container.update("");
60163 this.container.setStyle("overflow", "hidden");
60164 this.container.addClass('x-grid-container');
60166 this.id = this.container.id;
60168 Roo.apply(this, config);
60169 // check and correct shorthanded configs
60173 for (var r = 0;r < 6;r++) {
60176 for (var c =0;c < 7;c++) {
60180 if (this.eventStore) {
60181 this.eventStore= Roo.factory(this.eventStore, Roo.data);
60182 this.eventStore.on('load',this.onLoad, this);
60183 this.eventStore.on('beforeload',this.clearEvents, this);
60187 this.dataSource = new Roo.data.Store({
60188 proxy: new Roo.data.MemoryProxy(rows),
60189 reader: new Roo.data.ArrayReader({}, [
60190 'weekday0', 'weekday1', 'weekday2', 'weekday3', 'weekday4', 'weekday5', 'weekday6' ])
60193 this.dataSource.load();
60194 this.ds = this.dataSource;
60195 this.ds.xmodule = this.xmodule || false;
60198 var cellRender = function(v,x,r)
60200 return String.format(
60201 '<div class="fc-day fc-widget-content"><div>' +
60202 '<div class="fc-event-container"></div>' +
60203 '<div class="fc-day-number">{0}</div>'+
60205 '<div class="fc-day-content"><div style="position:relative"></div></div>' +
60206 '</div></div>', v);
60211 this.colModel = new Roo.grid.ColumnModel( [
60213 xtype: 'ColumnModel',
60215 dataIndex : 'weekday0',
60217 renderer : cellRender
60220 xtype: 'ColumnModel',
60222 dataIndex : 'weekday1',
60224 renderer : cellRender
60227 xtype: 'ColumnModel',
60229 dataIndex : 'weekday2',
60230 header : 'Tuesday',
60231 renderer : cellRender
60234 xtype: 'ColumnModel',
60236 dataIndex : 'weekday3',
60237 header : 'Wednesday',
60238 renderer : cellRender
60241 xtype: 'ColumnModel',
60243 dataIndex : 'weekday4',
60244 header : 'Thursday',
60245 renderer : cellRender
60248 xtype: 'ColumnModel',
60250 dataIndex : 'weekday5',
60252 renderer : cellRender
60255 xtype: 'ColumnModel',
60257 dataIndex : 'weekday6',
60258 header : 'Saturday',
60259 renderer : cellRender
60262 this.cm = this.colModel;
60263 this.cm.xmodule = this.xmodule || false;
60267 //this.selModel = new Roo.grid.CellSelectionModel();
60268 //this.sm = this.selModel;
60269 //this.selModel.init(this);
60273 this.container.setWidth(this.width);
60277 this.container.setHeight(this.height);
60284 * The raw click event for the entire grid.
60285 * @param {Roo.EventObject} e
60290 * The raw dblclick event for the entire grid.
60291 * @param {Roo.EventObject} e
60295 * @event contextmenu
60296 * The raw contextmenu event for the entire grid.
60297 * @param {Roo.EventObject} e
60299 "contextmenu" : true,
60302 * The raw mousedown event for the entire grid.
60303 * @param {Roo.EventObject} e
60305 "mousedown" : true,
60308 * The raw mouseup event for the entire grid.
60309 * @param {Roo.EventObject} e
60314 * The raw mouseover event for the entire grid.
60315 * @param {Roo.EventObject} e
60317 "mouseover" : true,
60320 * The raw mouseout event for the entire grid.
60321 * @param {Roo.EventObject} e
60326 * The raw keypress event for the entire grid.
60327 * @param {Roo.EventObject} e
60332 * The raw keydown event for the entire grid.
60333 * @param {Roo.EventObject} e
60341 * Fires when a cell is clicked
60342 * @param {Grid} this
60343 * @param {Number} rowIndex
60344 * @param {Number} columnIndex
60345 * @param {Roo.EventObject} e
60347 "cellclick" : true,
60349 * @event celldblclick
60350 * Fires when a cell is double clicked
60351 * @param {Grid} this
60352 * @param {Number} rowIndex
60353 * @param {Number} columnIndex
60354 * @param {Roo.EventObject} e
60356 "celldblclick" : true,
60359 * Fires when a row is clicked
60360 * @param {Grid} this
60361 * @param {Number} rowIndex
60362 * @param {Roo.EventObject} e
60366 * @event rowdblclick
60367 * Fires when a row is double clicked
60368 * @param {Grid} this
60369 * @param {Number} rowIndex
60370 * @param {Roo.EventObject} e
60372 "rowdblclick" : true,
60374 * @event headerclick
60375 * Fires when a header is clicked
60376 * @param {Grid} this
60377 * @param {Number} columnIndex
60378 * @param {Roo.EventObject} e
60380 "headerclick" : true,
60382 * @event headerdblclick
60383 * Fires when a header cell is double clicked
60384 * @param {Grid} this
60385 * @param {Number} columnIndex
60386 * @param {Roo.EventObject} e
60388 "headerdblclick" : true,
60390 * @event rowcontextmenu
60391 * Fires when a row is right clicked
60392 * @param {Grid} this
60393 * @param {Number} rowIndex
60394 * @param {Roo.EventObject} e
60396 "rowcontextmenu" : true,
60398 * @event cellcontextmenu
60399 * Fires when a cell is right clicked
60400 * @param {Grid} this
60401 * @param {Number} rowIndex
60402 * @param {Number} cellIndex
60403 * @param {Roo.EventObject} e
60405 "cellcontextmenu" : true,
60407 * @event headercontextmenu
60408 * Fires when a header is right clicked
60409 * @param {Grid} this
60410 * @param {Number} columnIndex
60411 * @param {Roo.EventObject} e
60413 "headercontextmenu" : true,
60415 * @event bodyscroll
60416 * Fires when the body element is scrolled
60417 * @param {Number} scrollLeft
60418 * @param {Number} scrollTop
60420 "bodyscroll" : true,
60422 * @event columnresize
60423 * Fires when the user resizes a column
60424 * @param {Number} columnIndex
60425 * @param {Number} newSize
60427 "columnresize" : true,
60429 * @event columnmove
60430 * Fires when the user moves a column
60431 * @param {Number} oldIndex
60432 * @param {Number} newIndex
60434 "columnmove" : true,
60437 * Fires when row(s) start being dragged
60438 * @param {Grid} this
60439 * @param {Roo.GridDD} dd The drag drop object
60440 * @param {event} e The raw browser event
60442 "startdrag" : true,
60445 * Fires when a drag operation is complete
60446 * @param {Grid} this
60447 * @param {Roo.GridDD} dd The drag drop object
60448 * @param {event} e The raw browser event
60453 * Fires when dragged row(s) are dropped on a valid DD target
60454 * @param {Grid} this
60455 * @param {Roo.GridDD} dd The drag drop object
60456 * @param {String} targetId The target drag drop object
60457 * @param {event} e The raw browser event
60462 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
60463 * @param {Grid} this
60464 * @param {Roo.GridDD} dd The drag drop object
60465 * @param {String} targetId The target drag drop object
60466 * @param {event} e The raw browser event
60471 * Fires when the dragged row(s) first cross another DD target while being dragged
60472 * @param {Grid} this
60473 * @param {Roo.GridDD} dd The drag drop object
60474 * @param {String} targetId The target drag drop object
60475 * @param {event} e The raw browser event
60477 "dragenter" : true,
60480 * Fires when the dragged row(s) leave another DD target while being dragged
60481 * @param {Grid} this
60482 * @param {Roo.GridDD} dd The drag drop object
60483 * @param {String} targetId The target drag drop object
60484 * @param {event} e The raw browser event
60489 * Fires when a row is rendered, so you can change add a style to it.
60490 * @param {GridView} gridview The grid view
60491 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
60497 * Fires when the grid is rendered
60498 * @param {Grid} grid
60503 * Fires when a date is selected
60504 * @param {DatePicker} this
60505 * @param {Date} date The selected date
60509 * @event monthchange
60510 * Fires when the displayed month changes
60511 * @param {DatePicker} this
60512 * @param {Date} date The selected month
60514 'monthchange': true,
60516 * @event evententer
60517 * Fires when mouse over an event
60518 * @param {Calendar} this
60519 * @param {event} Event
60521 'evententer': true,
60523 * @event eventleave
60524 * Fires when the mouse leaves an
60525 * @param {Calendar} this
60528 'eventleave': true,
60530 * @event eventclick
60531 * Fires when the mouse click an
60532 * @param {Calendar} this
60535 'eventclick': true,
60537 * @event eventrender
60538 * Fires before each cell is rendered, so you can modify the contents, like cls / title / qtip
60539 * @param {Calendar} this
60540 * @param {data} data to be modified
60542 'eventrender': true
60546 Roo.grid.Grid.superclass.constructor.call(this);
60547 this.on('render', function() {
60548 this.view.el.addClass('x-grid-cal');
60550 (function() { this.setDate(new Date()); }).defer(100,this); //default today..
60554 if (!Roo.grid.Calendar.style) {
60555 Roo.grid.Calendar.style = Roo.util.CSS.createStyleSheet({
60558 '.x-grid-cal .x-grid-col' : {
60559 height: 'auto !important',
60560 'vertical-align': 'top'
60562 '.x-grid-cal .fc-event-hori' : {
60573 Roo.extend(Roo.grid.Calendar, Roo.grid.Grid, {
60575 * @cfg {Store} eventStore The store that loads events.
60580 activeDate : false,
60583 monitorWindowResize : false,
60586 resizeColumns : function() {
60587 var col = (this.view.el.getWidth() / 7) - 3;
60588 // loop through cols, and setWidth
60589 for(var i =0 ; i < 7 ; i++){
60590 this.cm.setColumnWidth(i, col);
60593 setDate :function(date) {
60595 Roo.log('setDate?');
60597 this.resizeColumns();
60598 var vd = this.activeDate;
60599 this.activeDate = date;
60600 // if(vd && this.el){
60601 // var t = date.getTime();
60602 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
60603 // Roo.log('using add remove');
60605 // this.fireEvent('monthchange', this, date);
60607 // this.cells.removeClass("fc-state-highlight");
60608 // this.cells.each(function(c){
60609 // if(c.dateValue == t){
60610 // c.addClass("fc-state-highlight");
60611 // setTimeout(function(){
60612 // try{c.dom.firstChild.focus();}catch(e){}
60622 var days = date.getDaysInMonth();
60624 var firstOfMonth = date.getFirstDateOfMonth();
60625 var startingPos = firstOfMonth.getDay()-this.startDay;
60627 if(startingPos < this.startDay){
60631 var pm = date.add(Date.MONTH, -1);
60632 var prevStart = pm.getDaysInMonth()-startingPos;
60636 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
60638 this.textNodes = this.view.el.query('.x-grid-row .x-grid-col .x-grid-cell-text');
60639 //this.cells.addClassOnOver('fc-state-hover');
60641 var cells = this.cells.elements;
60642 var textEls = this.textNodes;
60644 //Roo.each(cells, function(cell){
60645 // cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
60648 days += startingPos;
60650 // convert everything to numbers so it's fast
60651 var day = 86400000;
60652 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
60655 //Roo.log(prevStart);
60657 var today = new Date().clearTime().getTime();
60658 var sel = date.clearTime().getTime();
60659 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
60660 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
60661 var ddMatch = this.disabledDatesRE;
60662 var ddText = this.disabledDatesText;
60663 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
60664 var ddaysText = this.disabledDaysText;
60665 var format = this.format;
60667 var setCellClass = function(cal, cell){
60669 //Roo.log('set Cell Class');
60671 var t = d.getTime();
60676 cell.dateValue = t;
60678 cell.className += " fc-today";
60679 cell.className += " fc-state-highlight";
60680 cell.title = cal.todayText;
60683 // disable highlight in other month..
60684 cell.className += " fc-state-highlight";
60689 //cell.className = " fc-state-disabled";
60690 cell.title = cal.minText;
60694 //cell.className = " fc-state-disabled";
60695 cell.title = cal.maxText;
60699 if(ddays.indexOf(d.getDay()) != -1){
60700 // cell.title = ddaysText;
60701 // cell.className = " fc-state-disabled";
60704 if(ddMatch && format){
60705 var fvalue = d.dateFormat(format);
60706 if(ddMatch.test(fvalue)){
60707 cell.title = ddText.replace("%0", fvalue);
60708 cell.className = " fc-state-disabled";
60712 if (!cell.initialClassName) {
60713 cell.initialClassName = cell.dom.className;
60716 cell.dom.className = cell.initialClassName + ' ' + cell.className;
60721 for(; i < startingPos; i++) {
60722 cells[i].dayName = (++prevStart);
60723 Roo.log(textEls[i]);
60724 d.setDate(d.getDate()+1);
60726 //cells[i].className = "fc-past fc-other-month";
60727 setCellClass(this, cells[i]);
60732 for(; i < days; i++){
60733 intDay = i - startingPos + 1;
60734 cells[i].dayName = (intDay);
60735 d.setDate(d.getDate()+1);
60737 cells[i].className = ''; // "x-date-active";
60738 setCellClass(this, cells[i]);
60742 for(; i < 42; i++) {
60743 //textEls[i].innerHTML = (++extraDays);
60745 d.setDate(d.getDate()+1);
60746 cells[i].dayName = (++extraDays);
60747 cells[i].className = "fc-future fc-other-month";
60748 setCellClass(this, cells[i]);
60751 //this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
60753 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
60755 // this will cause all the cells to mis
60758 for (var r = 0;r < 6;r++) {
60759 for (var c =0;c < 7;c++) {
60760 this.ds.getAt(r).set('weekday' + c ,cells[i++].dayName );
60764 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
60765 for(i=0;i<cells.length;i++) {
60767 this.cells.elements[i].dayName = cells[i].dayName ;
60768 this.cells.elements[i].className = cells[i].className;
60769 this.cells.elements[i].initialClassName = cells[i].initialClassName ;
60770 this.cells.elements[i].title = cells[i].title ;
60771 this.cells.elements[i].dateValue = cells[i].dateValue ;
60777 //this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
60778 //this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
60780 ////if(totalRows != 6){
60781 //this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
60782 // this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
60785 this.fireEvent('monthchange', this, date);
60790 * Returns the grid's SelectionModel.
60791 * @return {SelectionModel}
60793 getSelectionModel : function(){
60794 if(!this.selModel){
60795 this.selModel = new Roo.grid.CellSelectionModel();
60797 return this.selModel;
60801 this.eventStore.load()
60807 findCell : function(dt) {
60808 dt = dt.clearTime().getTime();
60810 this.cells.each(function(c){
60811 //Roo.log("check " +c.dateValue + '?=' + dt);
60812 if(c.dateValue == dt){
60822 findCells : function(rec) {
60823 var s = rec.data.start_dt.clone().clearTime().getTime();
60825 var e= rec.data.end_dt.clone().clearTime().getTime();
60828 this.cells.each(function(c){
60829 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
60831 if(c.dateValue > e){
60834 if(c.dateValue < s){
60843 findBestRow: function(cells)
60847 for (var i =0 ; i < cells.length;i++) {
60848 ret = Math.max(cells[i].rows || 0,ret);
60855 addItem : function(rec)
60857 // look for vertical location slot in
60858 var cells = this.findCells(rec);
60860 rec.row = this.findBestRow(cells);
60862 // work out the location.
60866 for(var i =0; i < cells.length; i++) {
60874 if (crow.start.getY() == cells[i].getY()) {
60876 crow.end = cells[i];
60892 for (var i = 0; i < cells.length;i++) {
60893 cells[i].rows = Math.max(cells[i].rows || 0 , rec.row + 1 );
60900 clearEvents: function() {
60902 if (!this.eventStore.getCount()) {
60905 // reset number of rows in cells.
60906 Roo.each(this.cells.elements, function(c){
60910 this.eventStore.each(function(e) {
60911 this.clearEvent(e);
60916 clearEvent : function(ev)
60919 Roo.each(ev.els, function(el) {
60920 el.un('mouseenter' ,this.onEventEnter, this);
60921 el.un('mouseleave' ,this.onEventLeave, this);
60929 renderEvent : function(ev,ctr) {
60931 ctr = this.view.el.select('.fc-event-container',true).first();
60935 this.clearEvent(ev);
60941 var cells = ev.cells;
60942 var rows = ev.rows;
60943 this.fireEvent('eventrender', this, ev);
60945 for(var i =0; i < rows.length; i++) {
60949 cls += ' fc-event-start';
60951 if ((i+1) == rows.length) {
60952 cls += ' fc-event-end';
60955 //Roo.log(ev.data);
60956 // how many rows should it span..
60957 var cg = this.eventTmpl.append(ctr,Roo.apply({
60960 }, ev.data) , true);
60963 cg.on('mouseenter' ,this.onEventEnter, this, ev);
60964 cg.on('mouseleave' ,this.onEventLeave, this, ev);
60965 cg.on('click', this.onEventClick, this, ev);
60969 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
60970 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
60973 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);
60974 cg.setWidth(ebox.right - sbox.x -2);
60978 renderEvents: function()
60980 // first make sure there is enough space..
60982 if (!this.eventTmpl) {
60983 this.eventTmpl = new Roo.Template(
60984 '<div class="roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable {fccls} {cls}" style="position: absolute" unselectable="on">' +
60985 '<div class="fc-event-inner">' +
60986 '<span class="fc-event-time">{time}</span>' +
60987 '<span class="fc-event-title" qtip="{qtip}">{title}</span>' +
60989 '<div class="ui-resizable-heandle ui-resizable-e"> </div>' +
60997 this.cells.each(function(c) {
60998 //Roo.log(c.select('.fc-day-content div',true).first());
60999 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, (c.rows || 1) * 20));
61002 var ctr = this.view.el.select('.fc-event-container',true).first();
61005 this.eventStore.each(function(ev){
61007 this.renderEvent(ev);
61011 this.view.layout();
61015 onEventEnter: function (e, el,event,d) {
61016 this.fireEvent('evententer', this, el, event);
61019 onEventLeave: function (e, el,event,d) {
61020 this.fireEvent('eventleave', this, el, event);
61023 onEventClick: function (e, el,event,d) {
61024 this.fireEvent('eventclick', this, el, event);
61027 onMonthChange: function () {
61031 onLoad: function () {
61033 //Roo.log('calendar onload');
61035 if(this.eventStore.getCount() > 0){
61039 this.eventStore.each(function(d){
61044 if (typeof(add.end_dt) == 'undefined') {
61045 Roo.log("Missing End time in calendar data: ");
61049 if (typeof(add.start_dt) == 'undefined') {
61050 Roo.log("Missing Start time in calendar data: ");
61054 add.start_dt = typeof(add.start_dt) == 'string' ? Date.parseDate(add.start_dt,'Y-m-d H:i:s') : add.start_dt,
61055 add.end_dt = typeof(add.end_dt) == 'string' ? Date.parseDate(add.end_dt,'Y-m-d H:i:s') : add.end_dt,
61056 add.id = add.id || d.id;
61057 add.title = add.title || '??';
61065 this.renderEvents();
61075 render : function ()
61079 if (!this.view.el.hasClass('course-timesheet')) {
61080 this.view.el.addClass('course-timesheet');
61082 if (this.tsStyle) {
61087 Roo.log(_this.grid.view.el.getWidth());
61090 this.tsStyle = Roo.util.CSS.createStyleSheet({
61091 '.course-timesheet .x-grid-row' : {
61094 '.x-grid-row td' : {
61095 'vertical-align' : 0
61097 '.course-edit-link' : {
61099 'text-overflow' : 'ellipsis',
61100 'overflow' : 'hidden',
61101 'white-space' : 'nowrap',
61102 'cursor' : 'pointer'
61107 '.de-act-sup-link' : {
61108 'color' : 'purple',
61109 'text-decoration' : 'line-through'
61113 'text-decoration' : 'line-through'
61115 '.course-timesheet .course-highlight' : {
61116 'border-top-style': 'dashed !important',
61117 'border-bottom-bottom': 'dashed !important'
61119 '.course-timesheet .course-item' : {
61120 'font-family' : 'tahoma, arial, helvetica',
61121 'font-size' : '11px',
61122 'overflow' : 'hidden',
61123 'padding-left' : '10px',
61124 'padding-right' : '10px',
61125 'padding-top' : '10px'
61133 monitorWindowResize : false,
61134 cellrenderer : function(v,x,r)
61139 xtype: 'CellSelectionModel',
61146 beforeload : function (_self, options)
61148 options.params = options.params || {};
61149 options.params._month = _this.monthField.getValue();
61150 options.params.limit = 9999;
61151 options.params['sort'] = 'when_dt';
61152 options.params['dir'] = 'ASC';
61153 this.proxy.loadResponse = this.loadResponse;
61155 //this.addColumns();
61157 load : function (_self, records, options)
61159 _this.grid.view.el.select('.course-edit-link', true).on('click', function() {
61160 // if you click on the translation.. you can edit it...
61161 var el = Roo.get(this);
61162 var id = el.dom.getAttribute('data-id');
61163 var d = el.dom.getAttribute('data-date');
61164 var t = el.dom.getAttribute('data-time');
61165 //var id = this.child('span').dom.textContent;
61168 Pman.Dialog.CourseCalendar.show({
61172 productitem_active : id ? 1 : 0
61174 _this.grid.ds.load({});
61179 _this.panel.fireEvent('resize', [ '', '' ]);
61182 loadResponse : function(o, success, response){
61183 // this is overridden on before load..
61185 Roo.log("our code?");
61186 //Roo.log(success);
61187 //Roo.log(response)
61188 delete this.activeRequest;
61190 this.fireEvent("loadexception", this, o, response);
61191 o.request.callback.call(o.request.scope, null, o.request.arg, false);
61196 result = o.reader.read(response);
61198 Roo.log("load exception?");
61199 this.fireEvent("loadexception", this, o, response, e);
61200 o.request.callback.call(o.request.scope, null, o.request.arg, false);
61203 Roo.log("ready...");
61204 // loop through result.records;
61205 // and set this.tdate[date] = [] << array of records..
61207 Roo.each(result.records, function(r){
61209 if(typeof(_this.tdata[r.data.when_dt.format('j')]) == 'undefined'){
61210 _this.tdata[r.data.when_dt.format('j')] = [];
61212 _this.tdata[r.data.when_dt.format('j')].push(r.data);
61215 //Roo.log(_this.tdata);
61217 result.records = [];
61218 result.totalRecords = 6;
61220 // let's generate some duumy records for the rows.
61221 //var st = _this.dateField.getValue();
61223 // work out monday..
61224 //st = st.add(Date.DAY, -1 * st.format('w'));
61226 var date = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
61228 var firstOfMonth = date.getFirstDayOfMonth();
61229 var days = date.getDaysInMonth();
61231 var firstAdded = false;
61232 for (var i = 0; i < result.totalRecords ; i++) {
61233 //var d= st.add(Date.DAY, i);
61236 for(var w = 0 ; w < 7 ; w++){
61237 if(!firstAdded && firstOfMonth != w){
61244 var dd = (d > 0 && d < 10) ? "0"+d : d;
61245 row['weekday'+w] = String.format(
61246 '<span style="font-size: 16px;"><b>{0}</b></span>'+
61247 '<span class="course-edit-link" style="color:blue;" data-id="0" data-date="{1}"> Add New</span>',
61249 date.format('Y-m-')+dd
61252 if(typeof(_this.tdata[d]) != 'undefined'){
61253 Roo.each(_this.tdata[d], function(r){
61257 var desc = (r.productitem_id_descrip) ? r.productitem_id_descrip : '';
61258 if(r.parent_id*1>0){
61259 is_sub = (r.productitem_id_visible*1 < 1) ? 'de-act-sup-link' :'sub-link';
61262 if(r.productitem_id_visible*1 < 1 && r.parent_id*1 < 1){
61263 deactive = 'de-act-link';
61266 row['weekday'+w] += String.format(
61267 '<br /><span class="course-edit-link {3} {4}" qtip="{5}" data-id="{0}">{2} - {1}</span>',
61269 r.product_id_name, //1
61270 r.when_dt.format('h:ia'), //2
61280 // only do this if something added..
61282 result.records.push(_this.grid.dataSource.reader.newRow(row));
61286 // push it twice. (second one with an hour..
61290 this.fireEvent("load", this, o, o.request.arg);
61291 o.request.callback.call(o.request.scope, result, o.request.arg, true);
61293 sortInfo : {field: 'when_dt', direction : 'ASC' },
61295 xtype: 'HttpProxy',
61298 url : baseURL + '/Roo/Shop_course.php'
61301 xtype: 'JsonReader',
61318 'name': 'parent_id',
61322 'name': 'product_id',
61326 'name': 'productitem_id',
61344 click : function (_self, e)
61346 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
61347 sd.setMonth(sd.getMonth()-1);
61348 _this.monthField.setValue(sd.format('Y-m-d'));
61349 _this.grid.ds.load({});
61355 xtype: 'Separator',
61359 xtype: 'MonthField',
61362 render : function (_self)
61364 _this.monthField = _self;
61365 // _this.monthField.set today
61367 select : function (combo, date)
61369 _this.grid.ds.load({});
61372 value : (function() { return new Date(); })()
61375 xtype: 'Separator',
61381 text : "Blue: in-active, green: in-active sup-event, red: de-active, purple: de-active sup-event"
61391 click : function (_self, e)
61393 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
61394 sd.setMonth(sd.getMonth()+1);
61395 _this.monthField.setValue(sd.format('Y-m-d'));
61396 _this.grid.ds.load({});
61409 * Ext JS Library 1.1.1
61410 * Copyright(c) 2006-2007, Ext JS, LLC.
61412 * Originally Released Under LGPL - original licence link has changed is not relivant.
61415 * <script type="text/javascript">
61419 * @class Roo.LoadMask
61420 * A simple utility class for generically masking elements while loading data. If the element being masked has
61421 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
61422 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
61423 * element's UpdateManager load indicator and will be destroyed after the initial load.
61425 * Create a new LoadMask
61426 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
61427 * @param {Object} config The config object
61429 Roo.LoadMask = function(el, config){
61430 this.el = Roo.get(el);
61431 Roo.apply(this, config);
61433 this.store.on('beforeload', this.onBeforeLoad, this);
61434 this.store.on('load', this.onLoad, this);
61435 this.store.on('loadexception', this.onLoadException, this);
61436 this.removeMask = false;
61438 var um = this.el.getUpdateManager();
61439 um.showLoadIndicator = false; // disable the default indicator
61440 um.on('beforeupdate', this.onBeforeLoad, this);
61441 um.on('update', this.onLoad, this);
61442 um.on('failure', this.onLoad, this);
61443 this.removeMask = true;
61447 Roo.LoadMask.prototype = {
61449 * @cfg {Boolean} removeMask
61450 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
61451 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
61454 * @cfg {String} msg
61455 * The text to display in a centered loading message box (defaults to 'Loading...')
61457 msg : 'Loading...',
61459 * @cfg {String} msgCls
61460 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
61462 msgCls : 'x-mask-loading',
61465 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
61471 * Disables the mask to prevent it from being displayed
61473 disable : function(){
61474 this.disabled = true;
61478 * Enables the mask so that it can be displayed
61480 enable : function(){
61481 this.disabled = false;
61484 onLoadException : function()
61486 Roo.log(arguments);
61488 if (typeof(arguments[3]) != 'undefined') {
61489 Roo.MessageBox.alert("Error loading",arguments[3]);
61493 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
61494 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
61501 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
61504 onLoad : function()
61506 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
61510 onBeforeLoad : function(){
61511 if(!this.disabled){
61512 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
61517 destroy : function(){
61519 this.store.un('beforeload', this.onBeforeLoad, this);
61520 this.store.un('load', this.onLoad, this);
61521 this.store.un('loadexception', this.onLoadException, this);
61523 var um = this.el.getUpdateManager();
61524 um.un('beforeupdate', this.onBeforeLoad, this);
61525 um.un('update', this.onLoad, this);
61526 um.un('failure', this.onLoad, this);
61531 * Ext JS Library 1.1.1
61532 * Copyright(c) 2006-2007, Ext JS, LLC.
61534 * Originally Released Under LGPL - original licence link has changed is not relivant.
61537 * <script type="text/javascript">
61542 * @class Roo.XTemplate
61543 * @extends Roo.Template
61544 * Provides a template that can have nested templates for loops or conditionals. The syntax is:
61546 var t = new Roo.XTemplate(
61547 '<select name="{name}">',
61548 '<tpl for="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
61552 // then append, applying the master template values
61555 * Supported features:
61560 {a_variable} - output encoded.
61561 {a_variable.format:("Y-m-d")} - call a method on the variable
61562 {a_variable:raw} - unencoded output
61563 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
61564 {a_variable:this.method_on_template(...)} - call a method on the template object.
61569 <tpl for="a_variable or condition.."></tpl>
61570 <tpl if="a_variable or condition"></tpl>
61571 <tpl exec="some javascript"></tpl>
61572 <tpl name="named_template"></tpl> (experimental)
61574 <tpl for="."></tpl> - just iterate the property..
61575 <tpl for=".."></tpl> - iterates with the parent (probably the template)
61579 Roo.XTemplate = function()
61581 Roo.XTemplate.superclass.constructor.apply(this, arguments);
61588 Roo.extend(Roo.XTemplate, Roo.Template, {
61591 * The various sub templates
61596 * basic tag replacing syntax
61599 * // you can fake an object call by doing this
61603 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
61606 * compile the template
61608 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
61611 compile: function()
61615 s = ['<tpl>', s, '</tpl>'].join('');
61617 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
61618 nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
61619 ifRe = /^<tpl\b[^>]*?if="(.*?)"/,
61620 execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
61621 namedRe = /^<tpl\b[^>]*?name="(\w+)"/, // named templates..
61626 while(true == !!(m = s.match(re))){
61627 var forMatch = m[0].match(nameRe),
61628 ifMatch = m[0].match(ifRe),
61629 execMatch = m[0].match(execRe),
61630 namedMatch = m[0].match(namedRe),
61635 name = forMatch && forMatch[1] ? forMatch[1] : '';
61638 // if - puts fn into test..
61639 exp = ifMatch && ifMatch[1] ? ifMatch[1] : null;
61641 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
61646 // exec - calls a function... returns empty if true is returned.
61647 exp = execMatch && execMatch[1] ? execMatch[1] : null;
61649 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
61657 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
61658 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
61659 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
61662 var uid = namedMatch ? namedMatch[1] : id;
61666 id: namedMatch ? namedMatch[1] : id,
61673 s = s.replace(m[0], '');
61675 s = s.replace(m[0], '{xtpl'+ id + '}');
61680 for(var i = tpls.length-1; i >= 0; --i){
61681 this.compileTpl(tpls[i]);
61682 this.tpls[tpls[i].id] = tpls[i];
61684 this.master = tpls[tpls.length-1];
61688 * same as applyTemplate, except it's done to one of the subTemplates
61689 * when using named templates, you can do:
61691 * var str = pl.applySubTemplate('your-name', values);
61694 * @param {Number} id of the template
61695 * @param {Object} values to apply to template
61696 * @param {Object} parent (normaly the instance of this object)
61698 applySubTemplate : function(id, values, parent)
61702 var t = this.tpls[id];
61706 if(t.test && !t.test.call(this, values, parent)){
61710 Roo.log("Xtemplate.applySubTemplate 'test': Exception thrown");
61711 Roo.log(e.toString());
61717 if(t.exec && t.exec.call(this, values, parent)){
61721 Roo.log("Xtemplate.applySubTemplate 'exec': Exception thrown");
61722 Roo.log(e.toString());
61727 var vs = t.target ? t.target.call(this, values, parent) : values;
61728 parent = t.target ? values : parent;
61729 if(t.target && vs instanceof Array){
61731 for(var i = 0, len = vs.length; i < len; i++){
61732 buf[buf.length] = t.compiled.call(this, vs[i], parent);
61734 return buf.join('');
61736 return t.compiled.call(this, vs, parent);
61738 Roo.log("Xtemplate.applySubTemplate : Exception thrown");
61739 Roo.log(e.toString());
61740 Roo.log(t.compiled);
61745 compileTpl : function(tpl)
61747 var fm = Roo.util.Format;
61748 var useF = this.disableFormats !== true;
61749 var sep = Roo.isGecko ? "+" : ",";
61750 var undef = function(str) {
61751 Roo.log("Property not found :" + str);
61755 var fn = function(m, name, format, args)
61757 //Roo.log(arguments);
61758 args = args ? args.replace(/\\'/g,"'") : args;
61759 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
61760 if (typeof(format) == 'undefined') {
61761 format= 'htmlEncode';
61763 if (format == 'raw' ) {
61767 if(name.substr(0, 4) == 'xtpl'){
61768 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
61771 // build an array of options to determine if value is undefined..
61773 // basically get 'xxxx.yyyy' then do
61774 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
61775 // (function () { Roo.log("Property not found"); return ''; })() :
61780 Roo.each(name.split('.'), function(st) {
61781 lookfor += (lookfor.length ? '.': '') + st;
61782 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
61785 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
61788 if(format && useF){
61790 args = args ? ',' + args : "";
61792 if(format.substr(0, 5) != "this."){
61793 format = "fm." + format + '(';
61795 format = 'this.call("'+ format.substr(5) + '", ';
61799 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
61803 // called with xxyx.yuu:(test,test)
61805 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
61807 // raw.. - :raw modifier..
61808 return "'"+ sep + udef_st + name + ")"+sep+"'";
61812 // branched to use + in gecko and [].join() in others
61814 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
61815 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
61818 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
61819 body.push(tpl.body.replace(/(\r\n|\n)/g,
61820 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
61821 body.push("'].join('');};};");
61822 body = body.join('');
61825 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
61827 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
61833 applyTemplate : function(values){
61834 return this.master.compiled.call(this, values, {});
61835 //var s = this.subs;
61838 apply : function(){
61839 return this.applyTemplate.apply(this, arguments);
61844 Roo.XTemplate.from = function(el){
61845 el = Roo.getDom(el);
61846 return new Roo.XTemplate(el.value || el.innerHTML);